diff options
author | Tor Norbye <tnorbye@google.com> | 2014-03-10 21:45:01 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-03-10 21:45:01 +0000 |
commit | 6466f2cf5c834b0b20b67010c7d88a5b080b7bdc (patch) | |
tree | 692580c33ff11dd96e405d07662f6c05d0c37642 | |
parent | dd7dafee94f064b00f0d3e30b87c7dfa234f16c6 (diff) | |
parent | 869f44d03c83dbaf7429b1c8c2ff82f33920dedf (diff) | |
download | idea-6466f2cf5c834b0b20b67010c7d88a5b080b7bdc.tar.gz |
Merge "Merge remote-tracking branch 'aosp/snapshot-master' into merge"
1069 files changed, 20597 insertions, 12054 deletions
diff --git a/.idea/libraries/Netty.xml b/.idea/libraries/Netty.xml index 8037545021dc..bc6600b3242d 100644 --- a/.idea/libraries/Netty.xml +++ b/.idea/libraries/Netty.xml @@ -1,11 +1,11 @@ <component name="libraryTable"> <library name="Netty"> <CLASSES> - <root url="jar://$PROJECT_DIR$/lib/netty-all-5.0.0.Alpha1.jar!/" /> + <root url="jar://$PROJECT_DIR$/lib/netty-all-5.0.0.Alpha2.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES> - <root url="jar://$PROJECT_DIR$/lib/src/netty-all-5.0.0.Alpha1-sources.jar!/" /> + <root url="jar://$PROJECT_DIR$/lib/src/netty-all-5.0.0.Alpha2-sources.jar!/" /> </SOURCES> </library> </component>
\ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 350f82e1c2fe..3da23322cd48 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -113,6 +113,8 @@ <module fileurl="file://$PROJECT_DIR$/jps/model-api/jps-model-api.iml" filepath="$PROJECT_DIR$/jps/model-api/jps-model-api.iml" group="jps" /> <module fileurl="file://$PROJECT_DIR$/jps/model-impl/jps-model-impl.iml" filepath="$PROJECT_DIR$/jps/model-impl/jps-model-impl.iml" group="jps" /> <module fileurl="file://$PROJECT_DIR$/jps/model-serialization/jps-model-serialization.iml" filepath="$PROJECT_DIR$/jps/model-serialization/jps-model-serialization.iml" group="jps" /> + <module fileurl="file://$PROJECT_DIR$/jps/model-impl/jps-model-tests.iml" filepath="$PROJECT_DIR$/jps/model-impl/jps-model-tests.iml" /> + <module fileurl="file://$PROJECT_DIR$/jps/model-serialization/jps-serialization-tests.iml" filepath="$PROJECT_DIR$/jps/model-serialization/jps-serialization-tests.iml" group="jps" /> <module fileurl="file://$PROJECT_DIR$/jps/standalone-builder/jps-standalone-builder.iml" filepath="$PROJECT_DIR$/jps/standalone-builder/jps-standalone-builder.iml" group="jps" /> <module fileurl="file://$PROJECT_DIR$/java/jsp-base-openapi/jsp-base-openapi.iml" filepath="$PROJECT_DIR$/java/jsp-base-openapi/jsp-base-openapi.iml" group="java" /> <module fileurl="file://$PROJECT_DIR$/java/jsp-openapi/jsp-openapi.iml" filepath="$PROJECT_DIR$/java/jsp-openapi/jsp-openapi.iml" group="java" /> diff --git a/bin/win/runnerw.exe b/bin/win/runnerw.exe Binary files differindex affd133776f7..5c5f103adca8 100644 --- a/bin/win/runnerw.exe +++ b/bin/win/runnerw.exe diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 4210c5cb90d1..c60b71cb5785 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -256,7 +256,7 @@ public def layoutCommunityPlugins(String home) { layoutCloud() dir("plugins") { - def simplePlugins = ["commander", "copyright", "java-i18n", "hg4idea", "github", "ui-designer-core"] //, "tasks-time-tracking"] + def simplePlugins = ["commander", "copyright", "java-i18n", "hg4idea", "github"] //, "tasks-time-tracking"] simplePlugins.each { layoutPlugin it @@ -710,9 +710,19 @@ def layoutAndroid() { } } - layoutPlugin("android-designer") { - jar("android-designer.jar") { - module("android-designer") + dir("android-designer") { + dir("lib") { + jar("resources_en.jar") { + module("ui-designer-core") { + patternset(refid: "resources.included") + } + } + jar("android-designer.jar") { + module("ui-designer-core") { + patternset(refid: "resources.excluded") + } + module("android-designer") + } } } } @@ -818,8 +828,8 @@ def layoutCommunityJps(String home, String target) { dir("test") { jar("jps-build-test.jar") { moduleTests("jps-builders") - moduleTests("jps-model-impl") - moduleTests("jps-model-serialization") + moduleTests("jps-model-tests") + moduleTests("jps-serialization-tests") } } jar("ant-jps-plugin.jar") { module("ant-jps-plugin") } diff --git a/community-main.iml b/community-main.iml index c9f5b259e12c..a56cb309b19f 100644 --- a/community-main.iml +++ b/community-main.iml @@ -96,6 +96,9 @@ <orderEntry type="module" module-name="manifest" /> <orderEntry type="module" module-name="xml-tests" scope="TEST" /> <orderEntry type="module" module-name="devkit-jps-plugin" scope="TEST" /> + <orderEntry type="module" module-name="jps-model-tests" scope="TEST" /> + <orderEntry type="module" module-name="jps-serialization-tests" scope="TEST" /> + <orderEntry type="module" module-name="ui-designer-jps-plugin" scope="TEST" /> <orderEntry type="module" module-name="ui-designer-jps-plugin" scope="TEST" /> <orderEntry type="module" module-name="java-tests" scope="TEST" /> <orderEntry type="module" module-name="community-tests" scope="TEST" /> diff --git a/community-resources/src/idea_community_about.png b/community-resources/src/idea_community_about.png Binary files differindex 871356c35677..2b5a763fd9c5 100644 --- a/community-resources/src/idea_community_about.png +++ b/community-resources/src/idea_community_about.png diff --git a/community-resources/src/idea_community_about@2x.png b/community-resources/src/idea_community_about@2x.png Binary files differindex caf2a3585ae6..f159fb0a2e56 100644 --- a/community-resources/src/idea_community_about@2x.png +++ b/community-resources/src/idea_community_about@2x.png diff --git a/community-resources/src/idea_community_logo.png b/community-resources/src/idea_community_logo.png Binary files differindex 057bb1673dcf..91a8153fe2dc 100644 --- a/community-resources/src/idea_community_logo.png +++ b/community-resources/src/idea_community_logo.png diff --git a/community-resources/src/idea_community_logo@2x.png b/community-resources/src/idea_community_logo@2x.png Binary files differindex 451e5f2898e4..1f2cfb1dcceb 100644 --- a/community-resources/src/idea_community_logo@2x.png +++ b/community-resources/src/idea_community_logo@2x.png diff --git a/images/src/org/intellij/images/index/ImageInfoIndex.java b/images/src/org/intellij/images/index/ImageInfoIndex.java index 28838b5e316d..f2db1b48fc33 100644 --- a/images/src/org/intellij/images/index/ImageInfoIndex.java +++ b/images/src/org/intellij/images/index/ImageInfoIndex.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. @@ -46,14 +46,14 @@ public class ImageInfoIndex extends SingleEntryFileBasedIndexExtension<ImageInfo private final DataExternalizer<ImageInfo> myValueExternalizer = new DataExternalizer<ImageInfo>() { @Override - public void save(final DataOutput out, final ImageInfo info) throws IOException { + public void save(@NotNull final DataOutput out, final ImageInfo info) throws IOException { DataInputOutputUtil.writeINT(out, info.width); DataInputOutputUtil.writeINT(out, info.height); DataInputOutputUtil.writeINT(out, info.bpp); } @Override - public ImageInfo read(final DataInput in) throws IOException { + public ImageInfo read(@NotNull final DataInput in) throws IOException { return new ImageInfo(DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in)); } }; @@ -83,16 +83,18 @@ public class ImageInfoIndex extends SingleEntryFileBasedIndexExtension<ImageInfo .fileScope(project, virtualFile)); } + @NotNull @Override public DataExternalizer<ImageInfo> getValueExternalizer() { return myValueExternalizer; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(ImageFileTypeManager.getInstance().getImageFileType()) { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return file.isInLocalFileSystem() && file.getLength() / 1024 < ourMaxImageSize ; diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/StateCache.java b/java/compiler/impl/src/com/intellij/compiler/impl/StateCache.java index bd56b6653b91..631988e17577 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/StateCache.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/StateCache.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. @@ -19,6 +19,7 @@ import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorStringDescriptor; import com.intellij.util.io.PersistentHashMap; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -92,11 +93,11 @@ public abstract class StateCache<T> { private PersistentHashMap<String, T> createMap(final File file) throws IOException { return new PersistentHashMap<String,T>(file, new EnumeratorStringDescriptor(), new DataExternalizer<T>() { - public void save(final DataOutput out, final T value) throws IOException { + public void save(@NotNull final DataOutput out, final T value) throws IOException { StateCache.this.write(value, out); } - public T read(final DataInput in) throws IOException { + public T read(@NotNull final DataInput in) throws IOException { return StateCache.this.read(in); } }); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index a20c6975baa8..411fa24b2978 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -80,7 +80,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.TranslatingCompilerFilesMonitor"); - private static final boolean ourDebugMode = false; + public static boolean ourDebugMode = false; private static final FileAttribute ourSourceFileAttribute = new FileAttribute("_make_source_file_info_", 3); private static final FileAttribute ourOutputFileAttribute = new FileAttribute("_make_output_file_info_", 3); @@ -89,7 +89,6 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { private final Object myDataLock = new Object(); private final TIntHashSet mySuspendedProjects = new TIntHashSet(); // projectId for all projects that should not be monitored - private volatile int myWatchedProjectsCount; private final TIntObjectHashMap<TIntHashSet> mySourcesToRecompile = new TIntObjectHashMap<TIntHashSet>(); // ProjectId->set of source file paths private PersistentHashMap<Integer, TIntObjectHashMap<Pair<Integer, Integer>>> myOutputRootsStorage; // ProjectId->map[moduleId->Pair(outputDirId, testOutputDirId)] @@ -196,7 +195,6 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { return; } FileUtil.createIfDoesntExist(CompilerPaths.getRebuildMarkerFile(project)); - --myWatchedProjectsCount; // cleanup internal structures to free memory mySourcesToRecompile.remove(projectId); myOutputsToDelete.remove(projectId); @@ -217,8 +215,8 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { public void watchProject(Project project) { synchronized (myDataLock) { - mySuspendedProjects.remove(getProjectId(project)); - ++myWatchedProjectsCount; + int projectId = getProjectId(project); + mySuspendedProjects.remove(projectId); } } @@ -600,7 +598,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { private void initOutputRootsFile(File rootsFile) throws IOException { myOutputRootsStorage = new PersistentHashMap<Integer, TIntObjectHashMap<Pair<Integer, Integer>>>(rootsFile, EnumeratorIntegerDescriptor.INSTANCE, new DataExternalizer<TIntObjectHashMap<Pair<Integer, Integer>>>() { - public void save(DataOutput out, TIntObjectHashMap<Pair<Integer, Integer>> value) throws IOException { + public void save(@NotNull DataOutput out, TIntObjectHashMap<Pair<Integer, Integer>> value) throws IOException { for (final TIntObjectIterator<Pair<Integer, Integer>> it = value.iterator(); it.hasNext();) { it.advance(); DataInputOutputUtil.writeINT(out, it.key()); @@ -610,7 +608,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } } - public TIntObjectHashMap<Pair<Integer, Integer>> read(DataInput in) throws IOException { + public TIntObjectHashMap<Pair<Integer, Integer>> read(@NotNull DataInput in) throws IOException { final DataInputStream _in = (DataInputStream)in; final TIntObjectHashMap<Pair<Integer, Integer>> map = new TIntObjectHashMap<Pair<Integer, Integer>>(); while (_in.available() > 0) { @@ -1476,7 +1474,6 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } public void beforeFileDeletion(@NotNull final VirtualFileEvent event) { - if (myWatchedProjectsCount == 0) return; final VirtualFile eventFile = event.getFile(); if ((LOG.isDebugEnabled() && eventFile.isDirectory()) || ourDebugMode) { final String message = "Processing file deletion: " + eventFile.getPresentableUrl(); @@ -1616,7 +1613,6 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } private void processNewFile(final VirtualFile file, final boolean notifyServer) { - if (myWatchedProjectsCount == 0) return; final Ref<Boolean> isInContent = Ref.create(false); ApplicationManager.getApplication().runReadAction(new Runnable() { // need read action to ensure that the project was not disposed during the iteration over the project list diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/generic/GenericCompilerCache.java b/java/compiler/impl/src/com/intellij/compiler/impl/generic/GenericCompilerCache.java index 5741b9cf7949..4db878623df7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/generic/GenericCompilerCache.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/generic/GenericCompilerCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -112,8 +112,8 @@ public class GenericCompilerCache<Key, SourceState, OutputState> { } public static class PersistentStateData<SourceState, OutputState> { - public final SourceState mySourceState; - public final OutputState myOutputState; + @NotNull public final SourceState mySourceState; + @NotNull public final OutputState myOutputState; private PersistentStateData(@NotNull SourceState sourceState, @NotNull OutputState outputState) { mySourceState = sourceState; @@ -139,14 +139,14 @@ public class GenericCompilerCache<Key, SourceState, OutputState> { } @Override - public void save(DataOutput out, KeyAndTargetData<Key> value) throws IOException { + public void save(@NotNull DataOutput out, KeyAndTargetData<Key> value) throws IOException { out.writeInt(value.myTarget); myKeyDescriptor.save(out, value.myKey); } @Override - public KeyAndTargetData<Key> read(DataInput in) throws IOException { + public KeyAndTargetData<Key> read(@NotNull DataInput in) throws IOException { int target = in.readInt(); final Key item = myKeyDescriptor.read(in); return getKeyAndTargetData(item, target); @@ -163,13 +163,13 @@ public class GenericCompilerCache<Key, SourceState, OutputState> { } @Override - public void save(DataOutput out, PersistentStateData<SourceState, OutputState> value) throws IOException { + public void save(@NotNull DataOutput out, PersistentStateData<SourceState, OutputState> value) throws IOException { mySourceStateExternalizer.save(out, value.mySourceState); myOutputStateExternalizer.save(out, value.myOutputState); } @Override - public PersistentStateData<SourceState, OutputState> read(DataInput in) throws IOException { + public PersistentStateData<SourceState, OutputState> read(@NotNull DataInput in) throws IOException { SourceState sourceState = mySourceStateExternalizer.read(in); OutputState outputState = myOutputStateExternalizer.read(in); return new PersistentStateData<SourceState,OutputState>(sourceState, outputState); diff --git a/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java b/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java index fb7a5c6eb280..006debb3b43a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/BackwardDependenciesStorage.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. @@ -357,7 +357,7 @@ public class BackwardDependenciesStorage implements Flushable, Disposable { } private static class MyDataExternalizer implements DataExternalizer<DependenciesSet> { - public void save(DataOutput out, DependenciesSet ds) throws IOException { + public void save(@NotNull DataOutput out, DependenciesSet ds) throws IOException { final TIntHashSet classes = new TIntHashSet(); final Map<Dependency.FieldRef, TIntHashSet> fieldsMap = new HashMap<Dependency.FieldRef, TIntHashSet>(); final Map<Dependency.MethodRef, TIntHashSet> methodsMap = new HashMap<Dependency.MethodRef, TIntHashSet>(); @@ -414,7 +414,7 @@ public class BackwardDependenciesStorage implements Flushable, Disposable { } } - public DependenciesSet read(DataInput in) throws IOException { + public DependenciesSet read(@NotNull DataInput in) throws IOException { final Set<ReferencerItem> set = new THashSet<ReferencerItem>(); int classesCount = in.readInt(); diff --git a/java/compiler/impl/src/com/intellij/compiler/make/Cache.java b/java/compiler/impl/src/com/intellij/compiler/make/Cache.java index 2e3d5543214b..f80cb8e5bcaa 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/Cache.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/Cache.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. @@ -25,6 +25,7 @@ import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorIntegerDescriptor; import com.intellij.util.io.PersistentHashMap; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; @@ -54,10 +55,10 @@ public class Cache { myStorePath = storePath; new File(storePath).mkdirs(); myQNameToClassInfoMap = new CachedPersistentHashMap<Integer, ClassInfo>(getOrCreateFile("classes"), EnumeratorIntegerDescriptor.INSTANCE, new DataExternalizer<ClassInfo>() { - public void save(DataOutput out, ClassInfo value) throws IOException { + public void save(@NotNull DataOutput out, ClassInfo value) throws IOException { value.save(out); } - public ClassInfo read(DataInput in) throws IOException { + public ClassInfo read(@NotNull DataInput in) throws IOException { return new ClassInfo(in); } }, cacheSize * 2) { @@ -71,11 +72,11 @@ public class Cache { myQNameToSubclassesMap = new CompilerDependencyStorage<Integer>(getOrCreateFile("subclasses"), EnumeratorIntegerDescriptor.INSTANCE, cacheSize); myRemoteQNames = new PersistentHashMap<Integer, Boolean>(getOrCreateFile("remote"), EnumeratorIntegerDescriptor.INSTANCE, new DataExternalizer<Boolean>() { - public void save(DataOutput out, Boolean value) throws IOException { + public void save(@NotNull DataOutput out, Boolean value) throws IOException { out.writeBoolean(value.booleanValue()); } - public Boolean read(DataInput in) throws IOException { + public Boolean read(@NotNull DataInput in) throws IOException { return in.readBoolean(); } }, cacheSize); diff --git a/java/compiler/impl/src/com/intellij/compiler/make/CompilerDependencyStorage.java b/java/compiler/impl/src/com/intellij/compiler/make/CompilerDependencyStorage.java index ea93f2193297..2466881b14fd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/CompilerDependencyStorage.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/CompilerDependencyStorage.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. @@ -40,14 +40,14 @@ public class CompilerDependencyStorage<Key> implements Flushable, Disposable { public CompilerDependencyStorage(File file, KeyDescriptor<Key> keyDescriptor, final int cacheSize) throws IOException { myMap = new PersistentHashMap<Key, int[]>(file, keyDescriptor, new DataExternalizer<int[]>() { - public void save(DataOutput out, int[] array) throws IOException { + public void save(@NotNull DataOutput out, int[] array) throws IOException { out.writeInt(array.length); for (int value : array) { out.writeInt(value); } } - public int[] read(DataInput in) throws IOException { + public int[] read(@NotNull DataInput in) throws IOException { final TIntHashSet set = new TIntHashSet(); DataInputStream stream = (DataInputStream)in; while(stream.available() > 0) { 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 13d9be0b5623..506580c351a4 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -928,6 +928,7 @@ public class BuildManager implements ApplicationComponent{ launcherCp.add(ClasspathBootstrap.getResourcePath(launcherClass)); launcherCp.add(compilerPath); ClasspathBootstrap.appendJavaCompilerClasspath(launcherCp); + launcherCp.addAll(BuildProcessClasspathManager.getLauncherClasspath(project)); cmdLine.addParameter("-classpath"); cmdLine.addParameter(classpathToString(launcherCp)); diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildProcessParametersProvider.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildProcessParametersProvider.java index 434633f3da47..1da1b5c26631 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildProcessParametersProvider.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildProcessParametersProvider.java @@ -27,10 +27,23 @@ import java.util.List; public abstract class BuildProcessParametersProvider { public static final ExtensionPointName<BuildProcessParametersProvider> EP_NAME = ExtensionPointName.create("com.intellij.buildProcess.parametersProvider"); + /** + * Override this method to include additional jars to the build process classpath + * @return list of paths to additional jars to be included to the build process classpath + */ public @NotNull List<String> getClassPath() { return Collections.emptyList(); } - + + /** + * Override this method to include additional jars to the build process launcher classpath. This may be needed if the plugin provides + * custom implementation of Java compiler which must be loaded by the same classloader as tools.jar + * @return list of paths to additional jars to be included to the build process launcher classpath + */ + public @NotNull List<String> getLauncherClassPath() { + return Collections.emptyList(); + } + public @NotNull List<String> getVMArguments() { return Collections.emptyList(); } diff --git a/java/compiler/impl/src/com/intellij/compiler/server/impl/BuildProcessClasspathManager.java b/java/compiler/impl/src/com/intellij/compiler/server/impl/BuildProcessClasspathManager.java index 2c06c2fb9eeb..5cef06dbab94 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/impl/BuildProcessClasspathManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/impl/BuildProcessClasspathManager.java @@ -141,4 +141,12 @@ public class BuildProcessClasspathManager { } return classpath; } + + public static List<String> getLauncherClasspath(Project project) { + final List<String> classpath = ContainerUtil.newArrayList(); + for (BuildProcessParametersProvider provider : project.getExtensions(BuildProcessParametersProvider.EP_NAME)) { + classpath.addAll(provider.getLauncherClassPath()); + } + return classpath; + } } diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/DummyPersistentState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/DummyPersistentState.java index b3d66ce575fb..495b5a08758f 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/DummyPersistentState.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/DummyPersistentState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -16,6 +16,7 @@ package com.intellij.openapi.compiler.generic; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -33,11 +34,11 @@ public class DummyPersistentState { private static class DummyPersistentStateExternalizer implements DataExternalizer<DummyPersistentState> { @Override - public void save(DataOutput out, DummyPersistentState value) throws IOException { + public void save(@NotNull DataOutput out, DummyPersistentState value) throws IOException { } @Override - public DummyPersistentState read(DataInput in) throws IOException { + public DummyPersistentState read(@NotNull DataInput in) throws IOException { return INSTANCE; } } diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java index e9ea9700af42..17739b154aa6 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -16,6 +16,7 @@ package com.intellij.openapi.compiler.generic; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -38,12 +39,12 @@ public class VirtualFilePersistentState { private static class VirtualFileStateExternalizer implements DataExternalizer<VirtualFilePersistentState> { @Override - public void save(DataOutput out, VirtualFilePersistentState value) throws IOException { + public void save(@NotNull DataOutput out, VirtualFilePersistentState value) throws IOException { out.writeLong(value.getSourceTimestamp()); } @Override - public VirtualFilePersistentState read(DataInput in) throws IOException { + public VirtualFilePersistentState read(@NotNull DataInput in) throws IOException { return new VirtualFilePersistentState(in.readLong()); } diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java index a22e80dd77de..cf74b55f6691 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -67,7 +67,7 @@ public class VirtualFileSetState { private byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, VirtualFileSetState value) throws IOException { + public void save(@NotNull DataOutput out, VirtualFileSetState value) throws IOException { final Map<String, Long> dependencies = value.myTimestamps; out.writeInt(dependencies.size()); for (Map.Entry<String, Long> entry : dependencies.entrySet()) { @@ -77,7 +77,7 @@ public class VirtualFileSetState { } @Override - public VirtualFileSetState read(DataInput in) throws IOException { + public VirtualFileSetState read(@NotNull DataInput in) throws IOException { final VirtualFileSetState state = new VirtualFileSetState(); int size = in.readInt(); while (size-- > 0) { diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileWithDependenciesState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileWithDependenciesState.java index 9f4a815304de..1b9aee4254a7 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileWithDependenciesState.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileWithDependenciesState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -63,7 +63,7 @@ public class VirtualFileWithDependenciesState { private byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, VirtualFileWithDependenciesState value) throws IOException { + public void save(@NotNull DataOutput out, VirtualFileWithDependenciesState value) throws IOException { out.writeLong(value.mySourceTimestamp); final Map<String, Long> dependencies = value.myDependencies; out.writeInt(dependencies.size()); @@ -74,7 +74,7 @@ public class VirtualFileWithDependenciesState { } @Override - public VirtualFileWithDependenciesState read(DataInput in) throws IOException { + public VirtualFileWithDependenciesState read(@NotNull DataInput in) throws IOException { final VirtualFileWithDependenciesState state = new VirtualFileWithDependenciesState(in.readLong()); int size = in.readInt(); while (size-- > 0) { diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java index 030e9484ba26..c0a547e817d1 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -19,6 +19,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.util.SmartList; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.IOUtil; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -31,7 +32,7 @@ public class ArtifactPackagingItemExternalizer implements DataExternalizer<Artif private byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, ArtifactPackagingItemOutputState value) throws IOException { + public void save(@NotNull DataOutput out, ArtifactPackagingItemOutputState value) throws IOException { out.writeInt(value.myDestinations.size()); for (Pair<String, Long> pair : value.myDestinations) { IOUtil.writeUTFFast(myBuffer, out, pair.getFirst()); @@ -40,7 +41,7 @@ public class ArtifactPackagingItemExternalizer implements DataExternalizer<Artif } @Override - public ArtifactPackagingItemOutputState read(DataInput in) throws IOException { + public ArtifactPackagingItemOutputState read(@NotNull DataInput in) throws IOException { int size = in.readInt(); SmartList<Pair<String, Long>> destinations = new SmartList<Pair<String, Long>>(); while (size-- > 0) { diff --git a/java/debugger/impl/src/com/intellij/debugger/InstanceFilter.java b/java/debugger/impl/src/com/intellij/debugger/InstanceFilter.java index 9ce095c038dc..09be13076ca1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/InstanceFilter.java +++ b/java/debugger/impl/src/com/intellij/debugger/InstanceFilter.java @@ -20,6 +20,9 @@ import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; import com.intellij.ui.classFilter.ClassFilter; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.util.xmlb.annotations.Transient; import org.jdom.Element; /** @@ -27,10 +30,13 @@ import org.jdom.Element; * Date: Aug 29, 2003 * Time: 2:49:27 PM */ +@Tag("instance-filter") public class InstanceFilter implements JDOMExternalizable{ public static final InstanceFilter[] EMPTY_ARRAY = new InstanceFilter[0]; - + + @Attribute("id") public long ID = 0; + @Attribute("enabled") public boolean ENABLED = true; public InstanceFilter() { @@ -41,10 +47,12 @@ public class InstanceFilter implements JDOMExternalizable{ this.ENABLED = ENABLED; } + @Transient public long getId() { return ID; } + @Transient public boolean isEnabled() { return ENABLED; } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java deleted file mode 100644 index 9ed769aee350..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.debugger.actions; - -import com.intellij.debugger.DebuggerManagerEx; -import com.intellij.debugger.ui.breakpoints.BreakpointFactory; -import com.intellij.debugger.ui.breakpoints.BreakpointPropertiesPanel; -import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.ui.popup.JBPopupListener; -import com.intellij.openapi.ui.popup.LightweightWindowEvent; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.util.ui.UIUtil; -import com.intellij.xdebugger.impl.actions.EditBreakpointActionHandler; -import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil; -import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsDialogFactory; -import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; - -public class JavaEditBreakpointActionHandler extends EditBreakpointActionHandler { - @Override - protected void doShowPopup(final Project project, final JComponent component, final Point whereToShow, final Object breakpoint) { - if (!(breakpoint instanceof BreakpointWithHighlighter)) { - return; - } - - final BreakpointWithHighlighter javaBreakpoint = (BreakpointWithHighlighter)breakpoint; - BreakpointFactory breakpointFactory = null; - for (BreakpointFactory factory : BreakpointFactory.EXTENSION_POINT_NAME.getExtensions()) { - if (factory.getBreakpointCategory().equals(javaBreakpoint.getCategory())) { - breakpointFactory = factory; - } - } - assert breakpointFactory != null : "can't find factory for breakpoint " + javaBreakpoint; - - final BreakpointPropertiesPanel propertiesPanel = breakpointFactory.createBreakpointPropertiesPanel(project, true); - assert propertiesPanel != null; - propertiesPanel.initFrom(javaBreakpoint, false); - - final JComponent mainPanel = propertiesPanel.getPanel(); - final JBPopupListener saveOnClose = new JBPopupListener.Adapter() { - @Override - public void onClosed(LightweightWindowEvent event) { - propertiesPanel.saveTo(javaBreakpoint); - propertiesPanel.dispose(); - DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().fireBreakpointChanged(javaBreakpoint); - } - }; - - final Runnable showMoreOptions = new Runnable() { - @Override - public void run() { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - BreakpointsDialogFactory.getInstance(project).showDialog(javaBreakpoint); - } - }); - } - }; - - final Balloon balloon = DebuggerUIUtil.showBreakpointEditor(project, mainPanel, whereToShow, component, showMoreOptions, breakpoint); - balloon.addListener(saveOnClose); - - propertiesPanel.setDelegate(new BreakpointPropertiesPanel.Delegate() { - @Override - public void showActionsPanel() { - propertiesPanel.setActionsPanelVisible(true); - balloon.hide(); - DebuggerUIUtil.showBreakpointEditor(project, mainPanel, whereToShow, component, showMoreOptions, breakpoint).addListener(saveOnClose); - } - }); - - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - IdeFocusManager.findInstance().requestFocus(mainPanel, true); - } - }); - } - - @Override - public boolean isEnabled(@NotNull Project project, AnActionEvent event) { - DataContext dataContext = event.getDataContext(); - Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - if (editor == null) { - return false; - } - final Pair<GutterIconRenderer,Object> pair = XBreakpointUtil.findSelectedBreakpoint(project, editor); - return pair.first != null && pair.second instanceof BreakpointWithHighlighter; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java index 89e32bc28683..498ee6d44417 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java @@ -35,6 +35,7 @@ import java.util.List; public class JumpToObjectAction extends DebuggerAction{ private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.JumpToObjectAction"); + @Override public void actionPerformed(AnActionEvent e) { DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext()); if(selectedNode == null) { @@ -55,6 +56,7 @@ public class JumpToObjectAction extends DebuggerAction{ debugProcess.getManagerThread().schedule(new NavigateCommand(debuggerContext, (ValueDescriptor)descriptor, debugProcess, e)); } + @Override public void update(final AnActionEvent e) { if(!isFirstStart(e)) { return; @@ -82,7 +84,7 @@ public class JumpToObjectAction extends DebuggerAction{ } } - private SourcePosition calcPosition(final ValueDescriptor descriptor, final DebugProcessImpl debugProcess) throws ClassNotLoadedException { + private static SourcePosition calcPosition(final ValueDescriptor descriptor, final DebugProcessImpl debugProcess) throws ClassNotLoadedException { final Value value = descriptor.getValue(); if(value == null) { return null; @@ -103,10 +105,11 @@ public class JumpToObjectAction extends DebuggerAction{ if(locations.size() > 0) { final Location location = locations.get(0); return ApplicationManager.getApplication().runReadAction(new Computable<SourcePosition>() { + @Override public SourcePosition compute() { SourcePosition position = debugProcess.getPositionManager().getSourcePosition(location); // adjust position for non-anonymous classes - if (clsType.name().indexOf("$") < 0) { + if (clsType.name().indexOf('$') < 0) { final PsiClass classAt = position != null? JVMNameUtil.getClassAt(position) : null; if (classAt != null) { final SourcePosition classPosition = SourcePosition.createFromElement(classAt); @@ -130,13 +133,15 @@ public class JumpToObjectAction extends DebuggerAction{ return null; } - private class NavigateCommand extends SourcePositionCommand { + private static class NavigateCommand extends SourcePositionCommand { public NavigateCommand(final DebuggerContextImpl debuggerContext, final ValueDescriptor descriptor, final DebugProcessImpl debugProcess, final AnActionEvent e) { super(debuggerContext, descriptor, debugProcess, e); } + @Override protected NavigateCommand createRetryCommand() { return new NavigateCommand(myDebuggerContext, myDescriptor, myDebugProcess, myActionEvent); } + @Override protected void doAction(final SourcePosition sourcePosition) { if (sourcePosition != null) { sourcePosition.navigate(true); @@ -144,19 +149,21 @@ public class JumpToObjectAction extends DebuggerAction{ } } - private class EnableCommand extends SourcePositionCommand { + private static class EnableCommand extends SourcePositionCommand { public EnableCommand(final DebuggerContextImpl debuggerContext, final ValueDescriptor descriptor, final DebugProcessImpl debugProcess, final AnActionEvent e) { super(debuggerContext, descriptor, debugProcess, e); } + @Override protected EnableCommand createRetryCommand() { return new EnableCommand(myDebuggerContext, myDescriptor, myDebugProcess, myActionEvent); } + @Override protected void doAction(final SourcePosition sourcePosition) { enableAction(myActionEvent, sourcePosition != null); } } - public abstract class SourcePositionCommand extends SuspendContextCommandImpl { + public abstract static class SourcePositionCommand extends SuspendContextCommandImpl { protected final DebuggerContextImpl myDebuggerContext; protected final ValueDescriptor myDescriptor; protected final DebugProcessImpl myDebugProcess; @@ -173,6 +180,7 @@ public class JumpToObjectAction extends DebuggerAction{ myActionEvent = actionEvent; } + @Override public final void contextAction() throws Exception { try { doAction(calcPosition(myDescriptor, myDebugProcess)); diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/QuickEvaluateActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/QuickEvaluateActionHandler.java index d67b2bf45572..6eedff4136ea 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/QuickEvaluateActionHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/QuickEvaluateActionHandler.java @@ -21,34 +21,37 @@ package com.intellij.debugger.actions; import com.intellij.debugger.DebuggerManagerEx; -import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.ui.ValueHint; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler; import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHint; +import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler; import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType; import org.jetbrains.annotations.NotNull; import java.awt.*; public class QuickEvaluateActionHandler extends QuickEvaluateHandler { - + @Override public boolean isEnabled(@NotNull final Project project) { DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(project).getContext().getDebuggerSession(); return debuggerSession != null && debuggerSession.isPaused(); } + @Override public AbstractValueHint createValueHint(@NotNull final Project project, @NotNull final Editor editor, @NotNull final Point point, final ValueHintType type) { return ValueHint.createValueHint(project, editor, point, type); } + @Override public boolean canShowHint(@NotNull final Project project) { DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(project).getContext().getDebuggerSession(); return debuggerSession != null && debuggerSession.isAttached(); } + @Override public int getValueLookupDelay(final Project project) { return DebuggerSettings.getInstance().VALUE_LOOKUP_DELAY; } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleBreakpointEnabledAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleBreakpointEnabledAction.java index fda3e6128a3e..693b7f4917a5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleBreakpointEnabledAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleBreakpointEnabledAction.java @@ -22,7 +22,6 @@ import com.intellij.debugger.ui.breakpoints.BreakpointManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -41,7 +40,7 @@ public class ToggleBreakpointEnabledAction extends AnAction { Breakpoint breakpoint = findBreakpoint(project); if (breakpoint != null) { final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager(); - breakpointManager.setBreakpointEnabled(breakpoint, !breakpoint.ENABLED); + breakpointManager.setBreakpointEnabled(breakpoint, !breakpoint.isEnabled()); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java index 39a397755a5e..a7e00ee0dd72 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java @@ -81,7 +81,7 @@ public class ToggleFieldBreakpointAction extends AnAction { long id = object.uniqueID(); InstanceFilter[] instanceFilters = new InstanceFilter[] { InstanceFilter.create(Long.toString(id))}; fieldBreakpoint.setInstanceFilters(instanceFilters); - fieldBreakpoint.INSTANCE_FILTERS_ENABLED = true; + fieldBreakpoint.setInstanceFiltersEnabled(true); } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleLineBreakpointActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleLineBreakpointActionHandler.java deleted file mode 100644 index 650e7c37cf70..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleLineBreakpointActionHandler.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.actions; - -import com.intellij.codeInsight.folding.impl.actions.ExpandRegionAction; -import com.intellij.debugger.DebuggerManagerEx; -import com.intellij.debugger.engine.DebuggerUtils; -import com.intellij.debugger.engine.requests.RequestManagerImpl; -import com.intellij.debugger.ui.breakpoints.Breakpoint; -import com.intellij.debugger.ui.breakpoints.BreakpointManager; -import com.intellij.debugger.ui.breakpoints.LineBreakpoint; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.FoldRegion; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.xdebugger.impl.actions.DebuggerActionHandler; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class ToggleLineBreakpointActionHandler extends DebuggerActionHandler { - - private final boolean myTemporary; - - public ToggleLineBreakpointActionHandler(boolean temporary) { - - myTemporary = temporary; - } - - public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) { - PlaceInDocument place = getPlace(project, event); - if (place != null) { - final Document document = place.getDocument(); - final int offset = place.getOffset(); - int line = document.getLineNumber(offset); - - VirtualFile file = FileDocumentManager.getInstance().getFile(document); - PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - if (DebuggerUtils.supportsJVMDebugging(file.getFileType()) || DebuggerUtils.supportsJVMDebugging(psiFile)) { - final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager(); - return breakpointManager.findBreakpoint(document, offset, LineBreakpoint.CATEGORY) != null || - LineBreakpoint.canAddLineBreakpoint(project, document, line); - } - } - - return false; - } - - public void perform(@NotNull final Project project, final AnActionEvent event) { - PlaceInDocument place = getPlace(project, event); - if(place == null) { - return; - } - - Editor editor = event.getData(CommonDataKeys.EDITOR); - ExpandRegionAction.expandRegionAtCaret(project, editor); - - Document document = place.getDocument(); - int line = document.getLineNumber(place.getOffset()); - if (editor != null && editor.getCaretModel().getVisualPosition().line != line) { - editor.getCaretModel().moveToOffset(place.getOffset()); - } - - DebuggerManagerEx debugManager = DebuggerManagerEx.getInstanceEx(project); - if (debugManager == null) { - return; - } - BreakpointManager manager = debugManager.getBreakpointManager(); - final Breakpoint breakpoint = manager.findBreakpoint(document, place.getOffset(), LineBreakpoint.CATEGORY); - if(breakpoint == null) { - LineBreakpoint lineBreakpoint = manager.addLineBreakpoint(document, line); - if(lineBreakpoint != null) { - lineBreakpoint.REMOVE_AFTER_HIT = myTemporary; - RequestManagerImpl.createRequests(lineBreakpoint); - } - } - else { - if (!breakpoint.REMOVE_AFTER_HIT && myTemporary) { - breakpoint.REMOVE_AFTER_HIT = true; - breakpoint.updateUI(); - } - else { - manager.removeBreakpoint(breakpoint); - } - } - } - - private static boolean containsOnlyDeclarations(int line, Document document, PsiFile file) { - int lineStart = document.getLineStartOffset(line); - int lineEnd = document.getLineEndOffset(line); - PsiElement start = file.findElementAt(lineStart); - PsiElement end = file.findElementAt(lineEnd - 1); - if (start == null || end == null) return false; - - PsiElement commonParent = PsiTreeUtil.findCommonParent(start, end); - for (PsiElement element : PsiTreeUtil.findChildrenOfAnyType(commonParent, PsiStatement.class, PsiExpression.class)) { - if (new TextRange(lineStart, lineEnd).contains(element.getTextRange().getStartOffset())) { - return false; - } - } - return true; - } - - @Nullable - private static PlaceInDocument getPlace(@NotNull final Project project, AnActionEvent event) { - Editor editor = event.getData(CommonDataKeys.EDITOR); - if(editor == null) { - editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); - } - if (editor == null) { - return null; - } - - final Document document = editor.getDocument(); - PsiDocumentManager.getInstance(project).commitDocument(document); - PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); - if (file == null) { - return null; - } - - // if several lines are merged into one visual line (using folding), try to find the most appropriate of those lines - int visualLine = editor.getCaretModel().getVisualPosition().getLine(); - int visibleOffset = editor.getCaretModel().getOffset(); - while (editor.offsetToVisualPosition(visibleOffset).line == visualLine) { - int line = document.getLineNumber(visibleOffset); - if (!containsOnlyDeclarations(line, document, file)) { - return new PlaceInDocument(document, visibleOffset); - } - int lineEndOffset = document.getLineEndOffset(line); - FoldRegion region = editor.getFoldingModel().getCollapsedRegionAtOffset(lineEndOffset); - if (region != null) { - int foldEnd = region.getEndOffset(); - if (foldEnd > lineEndOffset) { - visibleOffset = foldEnd; - continue; - } - } - visibleOffset = lineEndOffset + 1; - } - - return new PlaceInDocument(document, editor.getCaretModel().getOffset()); - } -}
\ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java index 49d3cae977f0..399c55fd00e5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java @@ -17,22 +17,24 @@ package com.intellij.debugger.engine; import com.intellij.debugger.NoDataException; import com.intellij.debugger.PositionManager; +import com.intellij.debugger.PositionManagerEx; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.requests.ClassPrepareRequestor; -import com.intellij.openapi.diagnostic.Logger; +import com.intellij.xdebugger.frame.XStackFrame; import com.sun.jdi.Location; import com.sun.jdi.ReferenceType; import com.sun.jdi.request.ClassPrepareRequest; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class CompoundPositionManager implements PositionManager{ - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.CompoundPositionManager"); +public class CompoundPositionManager extends PositionManagerEx { private final ArrayList<PositionManager> myPositionManagers = new ArrayList<PositionManager>(); + @SuppressWarnings("UnusedDeclaration") public CompoundPositionManager() { } @@ -45,6 +47,7 @@ public class CompoundPositionManager implements PositionManager{ myPositionManagers.add(0, manager); } + @Override public SourcePosition getSourcePosition(Location location) { for (PositionManager positionManager : myPositionManagers) { try { @@ -56,6 +59,7 @@ public class CompoundPositionManager implements PositionManager{ return null; } + @Override @NotNull public List<ReferenceType> getAllClasses(SourcePosition classPosition) { for (PositionManager positionManager : myPositionManagers) { @@ -68,6 +72,7 @@ public class CompoundPositionManager implements PositionManager{ return Collections.emptyList(); } + @Override @NotNull public List<Location> locationsOfLine(ReferenceType type, SourcePosition position) { for (PositionManager positionManager : myPositionManagers) { @@ -80,6 +85,7 @@ public class CompoundPositionManager implements PositionManager{ return Collections.emptyList(); } + @Override public ClassPrepareRequest createPrepareRequest(ClassPrepareRequestor requestor, SourcePosition position) { for (PositionManager positionManager : myPositionManagers) { try { @@ -91,4 +97,18 @@ public class CompoundPositionManager implements PositionManager{ return null; } + + @Nullable + @Override + public XStackFrame createStackFrame(@NotNull Location location) { + for (PositionManager positionManager : myPositionManagers) { + if (positionManager instanceof PositionManagerEx) { + XStackFrame xStackFrame = ((PositionManagerEx)positionManager).createStackFrame(location); + if (xStackFrame != null) { + return xStackFrame; + } + } + } + return null; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/ContextUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/ContextUtil.java index bfd7d050adc8..26903c87ca4f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/ContextUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/ContextUtil.java @@ -53,8 +53,8 @@ public class ContextUtil { try { location = frameProxy.location(); } - catch (Throwable th) { - LOG.debug(th); + catch (Throwable e) { + LOG.debug(e); } final CompoundPositionManager positionManager = debugProcess.getPositionManager(); if (positionManager == null) { @@ -63,7 +63,8 @@ public class ContextUtil { } try { return positionManager.getSourcePosition(location); - } catch (IndexNotReadyException e) { + } + catch (IndexNotReadyException ignored) { return null; } } @@ -124,10 +125,10 @@ public class ContextUtil { } return codeBlockFromText; } - catch (IncorrectOperationException e) { + catch (IncorrectOperationException ignored) { return element; } - catch (EvaluateException e) { + catch (EvaluateException ignored) { return element; } finally { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index a5b1be2ba733..b660d5f1ed6e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -57,9 +57,9 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.PsiDocumentManager; @@ -77,6 +77,7 @@ import com.sun.jdi.connect.*; import com.sun.jdi.request.EventRequest; import com.sun.jdi.request.EventRequestManager; import com.sun.jdi.request.StepRequest; +import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -88,7 +89,7 @@ import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -public abstract class DebugProcessImpl implements DebugProcess { +public abstract class DebugProcessImpl extends UserDataHolderBase implements DebugProcess { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebugProcessImpl"); @NonNls private static final String SOCKET_ATTACHING_CONNECTOR_NAME = "com.sun.jdi.SocketAttach"; @@ -111,26 +112,26 @@ public abstract class DebugProcessImpl implements DebugProcess { protected static final int STATE_DETACHED = 3; protected final AtomicInteger myState = new AtomicInteger(STATE_INITIAL); - private ExecutionResult myExecutionResult; + private ExecutionResult myExecutionResult; private RemoteConnection myConnection; private ConnectionServiceWrapper myConnectionService; private Map<String, Connector.Argument> myArguments; private final List<NodeRenderer> myRenderers = new ArrayList<NodeRenderer>(); - private final Map<Type, NodeRenderer> myNodeRederersMap = new com.intellij.util.containers.HashMap<Type, NodeRenderer>(); - private final NodeRendererSettingsListener mySettingsListener = new NodeRendererSettingsListener() { - public void renderersChanged() { - myNodeRederersMap.clear(); - myRenderers.clear(); - loadRenderers(); - } - }; + private final Map<Type, NodeRenderer> myNodeRenderersMap = new THashMap<Type, NodeRenderer>(); + private final NodeRendererSettingsListener mySettingsListener = new NodeRendererSettingsListener() { + @Override + public void renderersChanged() { + myNodeRenderersMap.clear(); + myRenderers.clear(); + loadRenderers(); + } + }; private final SuspendManagerImpl mySuspendManager = new SuspendManagerImpl(this); protected CompoundPositionManager myPositionManager = null; private volatile DebuggerManagerThreadImpl myDebuggerManagerThread; - private final HashMap myUserData = new HashMap(); private static final int LOCAL_START_TIMEOUT = 30000; private final Semaphore myWaitFor = new Semaphore(); @@ -141,9 +142,6 @@ public abstract class DebugProcessImpl implements DebugProcess { private final Disposable myDisposable = Disposer.newDisposable(); private final Alarm myStatusUpdateAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myDisposable); - /** @noinspection FieldCanBeLocal*/ - private volatile boolean myDebugProcessStarted = false; - protected DebugProcessImpl(Project project) { myProject = project; myRequestManager = new RequestManagerImpl(this); @@ -153,6 +151,7 @@ public abstract class DebugProcessImpl implements DebugProcess { private void loadRenderers() { getManagerThread().invoke(new DebuggerCommandImpl() { + @Override protected void action() throws Exception { try { final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance(); @@ -164,6 +163,7 @@ public abstract class DebugProcessImpl implements DebugProcess { } finally { DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() { + @Override public void run() { final DebuggerSession session = mySession; if (session != null && session.isAttached()) { @@ -215,7 +215,7 @@ public abstract class DebugProcessImpl implements DebugProcess { return getDefaultRenderer(type); } - NodeRenderer renderer = myNodeRederersMap.get(type); + NodeRenderer renderer = myNodeRenderersMap.get(type); if(renderer == null) { for (final NodeRenderer nodeRenderer : myRenderers) { if (nodeRenderer.isApplicable(type)) { @@ -226,7 +226,7 @@ public abstract class DebugProcessImpl implements DebugProcess { if (renderer == null) { renderer = getDefaultRenderer(type); } - myNodeRederersMap.put(type, renderer); + myNodeRenderersMap.put(type, renderer); } return renderer; @@ -308,7 +308,7 @@ public abstract class DebugProcessImpl implements DebugProcess { private void stopConnecting() { DebuggerManagerThreadImpl.assertIsManagerThread(); - Map arguments = myArguments; + Map<String, Connector.Argument> arguments = myArguments; try { if (arguments == null) { return; @@ -423,7 +423,7 @@ public abstract class DebugProcessImpl implements DebugProcess { final List<StepRequest> toDelete = new ArrayList<StepRequest>(stepRequests.size()); for (final StepRequest request : stepRequests) { ThreadReference threadReference = request.thread(); - // [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occures + // [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occurs try { if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN && (stepThread == null || stepThread.equals(threadReference))) { toDelete.add(request); @@ -444,7 +444,7 @@ public abstract class DebugProcessImpl implements DebugProcess { StackFrameProxyImpl stackFrame = thread.frame(0); if (stackFrame != null) { Location location = stackFrame.location(); - ReferenceType referenceType = location.declaringType(); + ReferenceType referenceType = location == null ? null : location.declaringType(); if (referenceType != null) { return referenceType.name(); } @@ -477,7 +477,7 @@ public abstract class DebugProcessImpl implements DebugProcess { if (address == null) { throw new CantRunException(DebuggerBundle.message("error.no.debug.listen.port")); } - // negative port number means the caller leaves to debugger to decide at which hport to listen + // negative port number means the caller leaves to debugger to decide at which port to listen //noinspection HardCodedStringLiteral final Connector.Argument portArg = myConnection.isUseSockets() ? myArguments.get("port") : myArguments.get("name"); if (portArg != null) { @@ -498,10 +498,10 @@ public abstract class DebugProcessImpl implements DebugProcess { try { connector.stopListening(myArguments); } - catch (IllegalArgumentException e) { + catch (IllegalArgumentException ignored) { // ignored } - catch (IllegalConnectorArgumentsException e) { + catch (IllegalConnectorArgumentsException ignored) { // ignored } } @@ -572,6 +572,7 @@ public abstract class DebugProcessImpl implements DebugProcess { if (!myStatusUpdateAlarm.isDisposed()) { myStatusUpdateAlarm.cancelAllRequests(); myStatusUpdateAlarm.addRequest(new Runnable() { + @Override public void run() { final WindowManager wm = WindowManager.getInstance(); if (wm != null) { @@ -614,6 +615,7 @@ public abstract class DebugProcessImpl implements DebugProcess { final String version = vm.version(); if ("1.4.0".equals(version)) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { Messages.showMessageDialog( getProject(), @@ -633,10 +635,12 @@ public abstract class DebugProcessImpl implements DebugProcess { myEvaluationDispatcher.removeListener(evaluationListener); } + @Override public void addDebugProcessListener(DebugProcessListener listener) { myDebugProcessDispatcher.addListener(listener); } + @Override public void removeDebugProcessListener(DebugProcessListener listener) { myDebugProcessDispatcher.removeListener(listener); } @@ -668,18 +672,12 @@ public abstract class DebugProcessImpl implements DebugProcess { return myConnection; } + @Override public ExecutionResult getExecutionResult() { return myExecutionResult; } - public <T> T getUserData(Key<T> key) { - return (T)myUserData.get(key); - } - - public <T> void putUserData(Key<T> key, T value) { - myUserData.put(key, value); - } - + @Override public Project getProject() { return myProject; } @@ -698,22 +696,27 @@ public abstract class DebugProcessImpl implements DebugProcess { return myState.get() == STATE_INITIAL; } + @Override public boolean isAttached() { return myState.get() == STATE_ATTACHED; } + @Override public boolean isDetached() { return myState.get() == STATE_DETACHED; } + @Override public boolean isDetaching() { return myState.get() == STATE_DETACHING; } + @Override public RequestManagerImpl getRequestsManager() { return myRequestManager; } + @Override public VirtualMachineProxyImpl getVirtualMachineProxy() { DebuggerManagerThreadImpl.assertIsManagerThread(); final VirtualMachineProxyImpl vm = myVirtualMachineProxy; @@ -723,6 +726,7 @@ public abstract class DebugProcessImpl implements DebugProcess { return vm; } + @Override public void appendPositionManager(final PositionManager positionManager) { DebuggerManagerThreadImpl.assertIsManagerThread(); myPositionManager.appendPositionManager(positionManager); @@ -756,7 +760,7 @@ public abstract class DebugProcessImpl implements DebugProcess { myVirtualMachineProxy = null; myPositionManager = null; myReturnValueWatcher = null; - myNodeRederersMap.clear(); + myNodeRenderersMap.clear(); myRenderers.clear(); DebuggerUtils.cleanupAfterProcessFinish(this); myState.set(STATE_DETACHED); @@ -852,6 +856,7 @@ public abstract class DebugProcessImpl implements DebugProcess { Disposer.dispose(myDisposable); } + @Override public DebuggerManagerThreadImpl getManagerThread() { if (myDebuggerManagerThread == null) { synchronized (this) { @@ -868,11 +873,13 @@ public abstract class DebugProcessImpl implements DebugProcess { return suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD ? ObjectReference.INVOKE_SINGLE_THREADED : 0; } + @Override public void waitFor() { LOG.assertTrue(!DebuggerManagerThreadImpl.isManagerThread()); myWaitFor.waitFor(); } + @Override public void waitFor(long timeout) { LOG.assertTrue(!DebuggerManagerThreadImpl.isManagerThread()); myWaitFor.waitFor(timeout); @@ -1002,6 +1009,7 @@ public abstract class DebugProcessImpl implements DebugProcess { final Exception[] exception = new Exception[1]; final Value[] result = new Value[1]; getManagerThread().startLongProcessAndFork(new Runnable() { + @Override public void run() { ThreadReferenceProxyImpl thread = context.getThread(); try { @@ -1075,14 +1083,17 @@ public abstract class DebugProcessImpl implements DebugProcess { } } + @Override public Value invokeMethod(final EvaluationContext evaluationContext, final ObjectReference objRef, final Method method, final List args) throws EvaluateException { return invokeInstanceMethod(evaluationContext, objRef, method, args, 0); } + @Override public Value invokeInstanceMethod(final EvaluationContext evaluationContext, final ObjectReference objRef, final Method method, final List args, final int invocationOptions) throws EvaluateException { final ThreadReference thread = getEvaluationThread(evaluationContext); return new InvokeCommand<Value>(args) { + @Override protected Value invokeMethod(int invokePolicy, final List args) throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException { if (LOG.isDebugEnabled()) { LOG.debug("Invoke " + method.name()); @@ -1100,12 +1111,14 @@ public abstract class DebugProcessImpl implements DebugProcess { return evaluationThread.getThreadReference(); } + @Override public Value invokeMethod(final EvaluationContext evaluationContext, final ClassType classType, final Method method, final List args) throws EvaluateException { final ThreadReference thread = getEvaluationThread(evaluationContext); InvokeCommand<Value> invokeCommand = new InvokeCommand<Value>(args) { + @Override protected Value invokeMethod(int invokePolicy, final List args) throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, @@ -1119,17 +1132,20 @@ public abstract class DebugProcessImpl implements DebugProcess { return invokeCommand.start((EvaluationContextImpl)evaluationContext, method); } + @Override public ArrayReference newInstance(final ArrayType arrayType, final int dimension) throws EvaluateException { return arrayType.newInstance(dimension); } + @Override public ObjectReference newInstance(final EvaluationContext evaluationContext, final ClassType classType, final Method method, final List args) throws EvaluateException { final ThreadReference thread = getEvaluationThread(evaluationContext); InvokeCommand<ObjectReference> invokeCommand = new InvokeCommand<ObjectReference>(args) { + @Override protected ObjectReference invokeMethod(int invokePolicy, final List args) throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, @@ -1181,6 +1197,7 @@ public abstract class DebugProcessImpl implements DebugProcess { showStatusText(""); } + @Override public ReferenceType findClass(EvaluationContext evaluationContext, String className, ClassLoaderReference classLoader) throws EvaluateException { try { @@ -1255,7 +1272,7 @@ public abstract class DebugProcessImpl implements DebugProcess { } } - @SuppressWarnings({"HardCodedStringLiteral"}) + @SuppressWarnings({"HardCodedStringLiteral", "SpellCheckingInspection"}) public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String qName, ClassLoaderReference classLoader) throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException, EvaluateException { @@ -1308,13 +1325,15 @@ public abstract class DebugProcessImpl implements DebugProcess { return mySuspendManager; } + @Override public CompoundPositionManager getPositionManager() { return myPositionManager; } //ManagerCommands + @Override public void stop(boolean forceTerminate) { - this.getManagerThread().terminateAndInvoke(createStopCommand(forceTerminate), DebuggerManagerThreadImpl.COMMAND_TIMEOUT); + getManagerThread().terminateAndInvoke(createStopCommand(forceTerminate), DebuggerManagerThreadImpl.COMMAND_TIMEOUT); } public StopCommand createStopCommand(boolean forceTerminate) { @@ -1328,10 +1347,12 @@ public abstract class DebugProcessImpl implements DebugProcess { myIsTerminateTargetVM = isTerminateTargetVM; } + @Override public Priority getPriority() { return Priority.HIGH; } + @Override protected void action() throws Exception { if (isAttached()) { final VirtualMachineProxyImpl virtualMachineProxy = getVirtualMachineProxy(); @@ -1339,8 +1360,7 @@ public abstract class DebugProcessImpl implements DebugProcess { virtualMachineProxy.exit(-1); } else { - // some VM's (like IBM VM 1.4.2 bundled with WebSpere) does not - // resume threads on dispose() like it should + // some VMs (like IBM VM 1.4.2 bundled with WebSphere) does not resume threads on dispose() like it should try { virtualMachineProxy.resume(); } @@ -1360,6 +1380,7 @@ public abstract class DebugProcessImpl implements DebugProcess { super(suspendContext); } + @Override public void contextAction() { showStatusText(DebuggerBundle.message("status.step.out")); final SuspendContextImpl suspendContext = getSuspendContext(); @@ -1391,6 +1412,7 @@ public abstract class DebugProcessImpl implements DebugProcess { null; } + @Override public void contextAction() { showStatusText(DebuggerBundle.message("status.step.into")); final SuspendContextImpl suspendContext = getSuspendContext(); @@ -1409,7 +1431,7 @@ public abstract class DebugProcessImpl implements DebugProcess { hint.setIgnoreFilters(myForcedIgnoreFilters || mySession.shouldIgnoreSteppingFilters()); applyThreadFilter(stepThread); if (myBreakpoint != null) { - myBreakpoint.SUSPEND_POLICY = suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? DebuggerSettings.SUSPEND_THREAD : DebuggerSettings.SUSPEND_ALL; + myBreakpoint.setSuspendPolicy(suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? DebuggerSettings.SUSPEND_THREAD : DebuggerSettings.SUSPEND_ALL); myBreakpoint.createRequest(suspendContext.getDebugProcess()); myRunToCursorBreakpoint = myBreakpoint; } @@ -1426,11 +1448,12 @@ public abstract class DebugProcessImpl implements DebugProcess { myIsIgnoreBreakpoints = ignoreBreakpoints; } + @Override public void contextAction() { showStatusText(DebuggerBundle.message("status.step.over")); final SuspendContextImpl suspendContext = getSuspendContext(); final ThreadReferenceProxyImpl stepThread = getContextThread(); - // need this hint whil stepping over for JSR45 support: + // need this hint while stepping over for JSR45 support: // several lines of generated java code may correspond to a single line in the source file, // from which the java code was generated RequestHint hint = new RequestHint(stepThread, suspendContext, StepRequest.STEP_OVER); @@ -1464,6 +1487,7 @@ public abstract class DebugProcessImpl implements DebugProcess { myRunToCursorBreakpoint = breakpointManager.addRunToCursorBreakpoint(document, lineIndex, ignoreBreakpoints); } + @Override public void contextAction() { showStatusText(DebuggerBundle.message("status.run.to.cursor")); cancelRunToCursorBreakpoint(); @@ -1476,8 +1500,7 @@ public abstract class DebugProcessImpl implements DebugProcess { } applyThreadFilter(getContextThread()); final SuspendContextImpl context = getSuspendContext(); - myRunToCursorBreakpoint.SUSPEND_POLICY = context.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? DebuggerSettings.SUSPEND_THREAD : DebuggerSettings.SUSPEND_ALL; - myRunToCursorBreakpoint.LOG_ENABLED = false; + myRunToCursorBreakpoint.setSuspendPolicy(context.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? DebuggerSettings.SUSPEND_THREAD : DebuggerSettings.SUSPEND_ALL); myRunToCursorBreakpoint.createRequest(context.getDebugProcess()); DebugProcessImpl.this.myRunToCursorBreakpoint = myRunToCursorBreakpoint; super.contextAction(); @@ -1494,10 +1517,12 @@ public abstract class DebugProcessImpl implements DebugProcess { myContextThread = contextThread != null ? contextThread : (suspendContext != null? suspendContext.getThread() : null); } + @Override public Priority getPriority() { return Priority.HIGH; } + @Override public void contextAction() { showStatusText(DebuggerBundle.message("status.process.resumed")); getSuspendManager().resume(getSuspendContext()); @@ -1524,6 +1549,7 @@ public abstract class DebugProcessImpl implements DebugProcess { public PauseCommand() { } + @Override public void action() { if (!isAttached() || getVirtualMachineProxy().isPausePressed()) { return; @@ -1544,6 +1570,7 @@ public abstract class DebugProcessImpl implements DebugProcess { myThread = thread; } + @Override public void contextAction() { if (getSuspendManager().isFrozen(myThread)) { getSuspendManager().unfreezeThread(myThread); @@ -1553,7 +1580,7 @@ public abstract class DebugProcessImpl implements DebugProcess { final Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(getSuspendManager(), myThread); for (SuspendContextImpl suspendContext : suspendingContexts) { if (suspendContext.getThread() == myThread) { - DebugProcessImpl.this.getManagerThread().invoke(createResumeCommand(suspendContext)); + getManagerThread().invoke(createResumeCommand(suspendContext)); } else { getSuspendManager().resumeThread(suspendContext, myThread); @@ -1569,6 +1596,7 @@ public abstract class DebugProcessImpl implements DebugProcess { myThread = thread; } + @Override protected void action() throws Exception { SuspendManager suspendManager = getSuspendManager(); if (!suspendManager.isFrozen(myThread)) { @@ -1585,6 +1613,7 @@ public abstract class DebugProcessImpl implements DebugProcess { myStackFrame = frameProxy; } + @Override public void contextAction() { final ThreadReferenceProxyImpl thread = myStackFrame.threadProxy(); try { @@ -1593,7 +1622,7 @@ public abstract class DebugProcessImpl implements DebugProcess { return; } } - catch (ObjectCollectedException e) { + catch (ObjectCollectedException ignored) { notifyCancelled(); return; } @@ -1606,6 +1635,7 @@ public abstract class DebugProcessImpl implements DebugProcess { if (myStackFrame.isBottom()) { DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() { + @Override public void run() { Messages.showMessageDialog(myProject, DebuggerBundle.message("error.pop.bottom.stackframe"), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon()); } @@ -1618,6 +1648,7 @@ public abstract class DebugProcessImpl implements DebugProcess { } catch (final EvaluateException e) { DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() { + @Override public void run() { Messages.showMessageDialog(myProject, DebuggerBundle.message("error.pop.stackframe", e.getLocalizedMessage()), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon()); } @@ -1630,6 +1661,7 @@ public abstract class DebugProcessImpl implements DebugProcess { } } + @Override @NotNull public GlobalSearchScope getSearchScope() { LOG.assertTrue(mySession != null, "Accessing debug session before its initialization"); @@ -1668,7 +1700,6 @@ public abstract class DebugProcessImpl implements DebugProcess { } // writing to volatile field ensures the other threads will see the right values in non-volatile fields - myDebugProcessStarted = true; if (ApplicationManager.getApplication().isUnitTestMode()) { return myExecutionResult; @@ -1719,6 +1750,7 @@ public abstract class DebugProcessImpl implements DebugProcess { final Ref<Boolean> connectorIsReady = Ref.create(false); myDebugProcessDispatcher.addListener(new DebugProcessAdapter() { + @Override public void connectorIsReady() { connectorIsReady.set(true); semaphore.up(); @@ -1727,7 +1759,8 @@ public abstract class DebugProcessImpl implements DebugProcess { }); - this.getManagerThread().schedule(new DebuggerCommandImpl() { + getManagerThread().schedule(new DebuggerCommandImpl() { + @Override protected void action() { VirtualMachine vm = null; @@ -1744,7 +1777,7 @@ public abstract class DebugProcessImpl implements DebugProcess { try { wait(500); } - catch (InterruptedException ie) { + catch (InterruptedException ignored) { break; } } @@ -1752,10 +1785,11 @@ public abstract class DebugProcessImpl implements DebugProcess { else { fail(); if (myExecutionResult != null || !connectorIsReady.get()) { - // propagate exception only in case we succeded to obtain execution result, + // propagate exception only in case we succeeded to obtain execution result, // otherwise if the error is induced by the fact that there is nothing to debug, and there is no need to show // this problem to the user SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { ExecutionUtil.handleExecutionError(myProject, ToolWindowId.DEBUG, sessionName, e); } @@ -1773,8 +1807,10 @@ public abstract class DebugProcessImpl implements DebugProcess { if (vm != null) { final VirtualMachine vm1 = vm; afterProcessStarted(new Runnable() { + @Override public void run() { getManagerThread().schedule(new DebuggerCommandImpl() { + @Override protected void action() throws Exception { commitVM(vm1); } @@ -1784,6 +1820,7 @@ public abstract class DebugProcessImpl implements DebugProcess { } } + @Override protected void commandCancelled() { try { super.commandCancelled(); @@ -1809,6 +1846,7 @@ public abstract class DebugProcessImpl implements DebugProcess { removeProcessListener(this); } + @Override public void startNotified(ProcessEvent event) { run(); } @@ -1838,11 +1876,13 @@ public abstract class DebugProcessImpl implements DebugProcess { public ResumeCommand createResumeCommand(SuspendContextImpl suspendContext, final PrioritizedTask.Priority priority) { final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager(); return new ResumeCommand(suspendContext) { + @Override public void contextAction() { breakpointManager.applyThreadFilter(DebugProcessImpl.this, null); // clear the filter on resume super.contextAction(); } + @Override public Priority getPriority() { return priority; } @@ -1889,6 +1929,7 @@ public abstract class DebugProcessImpl implements DebugProcess { public void setBreakpointsMuted(final boolean muted) { if (isAttached()) { getManagerThread().schedule(new DebuggerCommandImpl() { + @Override protected void action() throws Exception { // set the flag before enabling/disabling cause it affects if breakpoints will create requests if (myBreakpointsMuted.getAndSet(muted) != muted) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/LocatableEventRequestor.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/LocatableEventRequestor.java index db64d1d1b553..ed1d7af2e16f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/requests/LocatableEventRequestor.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/LocatableEventRequestor.java @@ -19,16 +19,9 @@ import com.intellij.debugger.engine.events.SuspendContextCommandImpl; import com.intellij.debugger.requests.Requestor; import com.sun.jdi.event.LocatableEvent; -/** - * Created by IntelliJ IDEA. - * User: lex - * Date: Jun 27, 2003 - * Time: 8:05:52 PM - * To change this template use Options | File Templates. - */ public interface LocatableEventRequestor extends Requestor { /** - * @returns true if requesto was hit by the event, false otherwise + * @returns true if request was hit by the event, false otherwise */ boolean processLocatableEvent(SuspendContextCommandImpl action, LocatableEvent event) throws EventProcessingException; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java index 832958759964..c35c971c5a76 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java @@ -30,9 +30,7 @@ import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.debugger.ui.breakpoints.BreakpointManager; import com.intellij.debugger.ui.breakpoints.FilteredRequestor; -import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; @@ -40,15 +38,10 @@ import com.intellij.openapi.util.Key; import com.intellij.psi.PsiClass; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.util.containers.HashMap; -import com.intellij.xdebugger.XDebuggerManager; -import com.intellij.xdebugger.breakpoints.XBreakpointProperties; -import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.sun.jdi.*; import com.sun.jdi.event.ClassPrepareEvent; import com.sun.jdi.request.*; import org.jetbrains.annotations.Nullable; -import org.jetbrains.java.debugger.breakpoints.JavaBreakpointAdapter; -import org.jetbrains.java.debugger.breakpoints.JavaBreakpointType; import java.util.Collections; import java.util.HashSet; @@ -158,11 +151,11 @@ public class RequestManagerImpl extends DebugProcessAdapterImpl implements Reque request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); } - if (requestor.COUNT_FILTER_ENABLED && requestor.COUNT_FILTER > 0) { - request.addCountFilter(requestor.COUNT_FILTER); + if (requestor.isCountFilterEnabled() && requestor.getCountFilter() > 0) { + request.addCountFilter(requestor.getCountFilter()); } - if (requestor.CLASS_FILTERS_ENABLED && !(request instanceof BreakpointRequest) /*no built-in class filters support for breakpoint requests*/ ) { + if (requestor.isClassFiltersEnabled() && !(request instanceof BreakpointRequest) /*no built-in class filters support for breakpoint requests*/ ) { ClassFilter[] classFilters = requestor.getClassFilters(); if (DebuggerUtilsEx.getEnabledNumber(classFilters) == 1) { for (final ClassFilter filter : classFilters) { @@ -408,17 +401,18 @@ public class RequestManagerImpl extends DebugProcessAdapterImpl implements Reque breakpoint.createRequest(myDebugProcess); } - AccessToken token = ReadAction.start(); - try { - JavaBreakpointAdapter adapter = new JavaBreakpointAdapter(project); - for (XLineBreakpoint<XBreakpointProperties> breakpoint : XDebuggerManager.getInstance(project).getBreakpointManager() - .getBreakpoints(JavaBreakpointType.class)) { - adapter.getOrCreate(breakpoint).createRequest(myDebugProcess); - } - } - finally { - token.finish(); - } + //AccessToken token = ReadAction.start(); + //try { + // JavaBreakpointAdapter adapter = new JavaBreakpointAdapter(project); + // for (XLineBreakpoint breakpoint : XDebuggerManager.getInstance(project).getBreakpointManager() + // .getBreakpoints(JavaLineBreakpointType.class)) { + // //new JavaLineBreakpointRequestor(breakpoint).createRequest(myDebugProcess); + // //adapter.getOrCreate(breakpoint).createRequest(myDebugProcess); + // } + //} + //finally { + // token.finish(); + //} } }); } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java index e35ba834a9b5..640f76cad628 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java @@ -42,7 +42,7 @@ import org.jetbrains.annotations.Nullable; public final class DebuggerContextImpl implements DebuggerContext { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerContextImpl"); - public static final DebuggerContextImpl EMPTY_CONTEXT = DebuggerContextImpl.createDebuggerContext((DebuggerSession) null, null, null, null); + public static final DebuggerContextImpl EMPTY_CONTEXT = createDebuggerContext((DebuggerSession)null, null, null, null); private boolean myInitialized; @@ -58,7 +58,7 @@ public final class DebuggerContextImpl implements DebuggerContext { private DebuggerContextImpl(@Nullable DebuggerSession session, DebugProcessImpl debugProcess, SuspendContextImpl context, ThreadReferenceProxyImpl threadProxy, StackFrameProxyImpl frameProxy, SourcePosition position, PsiElement contextElement, boolean initialized) { LOG.assertTrue(frameProxy == null || threadProxy == null || threadProxy == frameProxy.threadProxy()); - LOG.assertTrue(debugProcess == null ? frameProxy == null && threadProxy == null : true); + LOG.assertTrue(debugProcess != null || frameProxy == null && threadProxy == null); myDebuggerSession = session; myThreadProxy = threadProxy; myFrameProxy = frameProxy; @@ -74,6 +74,7 @@ public final class DebuggerContextImpl implements DebuggerContext { return myDebuggerSession; } + @Override public DebugProcessImpl getDebugProcess() { return myDebugProcess; } @@ -82,14 +83,17 @@ public final class DebuggerContextImpl implements DebuggerContext { return myThreadProxy; } + @Override public SuspendContextImpl getSuspendContext() { return mySuspendContext; } + @Override public Project getProject() { return myDebugProcess != null ? myDebugProcess.getProject() : null; } + @Override @Nullable public StackFrameProxyImpl getFrameProxy() { LOG.assertTrue(myInitialized); @@ -144,13 +148,14 @@ public final class DebuggerContextImpl implements DebuggerContext { try { myFrameProxy = myThreadProxy.frameCount() > 0 ? myThreadProxy.frame(0) : null; } - catch (EvaluateException e) { + catch (EvaluateException ignored) { } } } if(myFrameProxy != null) { PsiDocumentManager.getInstance(getProject()).commitAndRunReadAction(new Runnable() { + @Override public void run() { if (mySourcePosition == null) { mySourcePosition = ContextUtil.getSourcePosition(DebuggerContextImpl.this); diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java index 917dba29b5a8..7837eab31aa8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java @@ -16,7 +16,6 @@ package com.intellij.debugger.impl; import com.intellij.debugger.*; -import com.intellij.debugger.actions.DebuggerActions; import com.intellij.debugger.engine.*; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationListener; @@ -56,6 +55,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.unscramble.ThreadState; import com.intellij.util.Alarm; import com.intellij.xdebugger.AbstractDebuggerSession; +import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager; import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.ThreadReference; @@ -115,6 +115,7 @@ public class DebuggerSession implements AbstractDebuggerSession { @NotNull public GlobalSearchScope getSearchScope() { + //noinspection ConstantConditions LOG.assertTrue(mySearchScope != null, "Accessing Session's search scope before its initialization"); return mySearchScope; } @@ -134,6 +135,7 @@ public class DebuggerSession implements AbstractDebuggerSession { myDebuggerContext = SESSION_EMPTY_CONTEXT; } + @Override public DebuggerContextImpl getContext() { return myDebuggerContext; } @@ -146,11 +148,13 @@ public class DebuggerSession implements AbstractDebuggerSession { * in this case we assume that the latter setState is ignored * since the thread was resumed */ + @Override public void setState(final DebuggerContextImpl context, final int state, final int event, final String description) { ApplicationManager.getApplication().assertIsDispatchThread(); final DebuggerSession session = context.getDebuggerSession(); LOG.assertTrue(session == DebuggerSession.this || session == null); final Runnable setStateRunnable = new Runnable() { + @Override public void run() { LOG.assertTrue(myDebuggerContext.isInitialised()); myDebuggerContext = context; @@ -170,6 +174,7 @@ public class DebuggerSession implements AbstractDebuggerSession { } else { getProcess().getManagerThread().schedule(new SuspendContextCommandImpl(context.getSuspendContext()) { + @Override public void contextAction() throws Exception { context.initCaches(); DebuggerInvocationUtil.swingInvokeLater(getProject(), setStateRunnable); @@ -279,7 +284,7 @@ public class DebuggerSession implements AbstractDebuggerSession { resumeAction(runToCursorCommand, EVENT_STEP); } catch (EvaluateException e) { - Messages.showErrorDialog(e.getMessage(), ActionsBundle.actionText(DebuggerActions.RUN_TO_CURSOR)); + Messages.showErrorDialog(e.getMessage(), ActionsBundle.actionText(XDebuggerActions.RUN_TO_CURSOR)); } } @@ -335,6 +340,7 @@ public class DebuggerSession implements AbstractDebuggerSession { } // ManagerCommands + @Override public boolean isStopped() { return getState() == STATE_STOPPED; } @@ -343,6 +349,7 @@ public class DebuggerSession implements AbstractDebuggerSession { return !isStopped() && getState() != STATE_WAITING_ATTACH; } + @Override public boolean isPaused() { return getState() == STATE_PAUSED; } @@ -399,18 +406,21 @@ public class DebuggerSession implements AbstractDebuggerSession { } //executed in manager thread + @Override public void connectorIsReady() { DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + @Override public void run() { RemoteConnection connection = myDebugProcess.getConnection(); final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection); final String transportName = DebuggerBundle.getTransportName(connection); final String connectionStatusMessage = connection.isServerMode() ? DebuggerBundle.message("status.listening", addressDisplayName, transportName) : DebuggerBundle.message("status.connecting", addressDisplayName, transportName); - getContextManager().setState(SESSION_EMPTY_CONTEXT, DebuggerSession.STATE_WAITING_ATTACH, DebuggerSession.EVENT_START_WAIT_ATTACH, connectionStatusMessage); + getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_WAITING_ATTACH, EVENT_START_WAIT_ATTACH, connectionStatusMessage); } }); } + @Override public void paused(final SuspendContextImpl suspendContext) { if (LOG.isDebugEnabled()) { LOG.debug("paused"); @@ -418,6 +428,7 @@ public class DebuggerSession implements AbstractDebuggerSession { if (!shouldSetAsActiveContext(suspendContext)) { DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + @Override public void run() { getContextManager().fireStateChanged(getContextManager().getContext(), EVENT_THREADS_REFRESH); } @@ -470,7 +481,7 @@ public class DebuggerSession implements AbstractDebuggerSession { } proxy = (currentThread.frameCount() > 0) ? currentThread.frame(0) : null; } - catch (ObjectCollectedException e) { + catch (ObjectCollectedException ignored) { proxy = null; } catch (EvaluateException e) { @@ -498,6 +509,7 @@ public class DebuggerSession implements AbstractDebuggerSession { } SourcePosition position = PsiDocumentManager.getInstance(getProject()).commitAndRunReadAction(new Computable<SourcePosition>() { + @Override public @Nullable SourcePosition compute() { return ContextUtil.getSourcePosition(positionContext); } @@ -507,7 +519,7 @@ public class DebuggerSession implements AbstractDebuggerSession { final List<Pair<Breakpoint, Event>> eventDescriptors = DebuggerUtilsEx.getEventDescriptors(suspendContext); final RequestManagerImpl requestsManager = suspendContext.getDebugProcess().getRequestsManager(); final PsiFile foundFile = position.getFile(); - final boolean sourceMissing = foundFile == null || foundFile instanceof PsiCompiledElement; + final boolean sourceMissing = foundFile instanceof PsiCompiledElement; for (Pair<Breakpoint, Event> eventDescriptor : eventDescriptors) { Breakpoint breakpoint = eventDescriptor.getFirst(); if (breakpoint instanceof LineBreakpoint) { @@ -525,7 +537,7 @@ public class DebuggerSession implements AbstractDebuggerSession { try { className = frameProxy != null? frameProxy.location().declaringType().name() : ""; } - catch (EvaluateException e) { + catch (EvaluateException ignored) { className = ""; } requestsManager.setInvalid(breakpoint, DebuggerBundle.message("error.invalid.breakpoint.source.not.found", className)); @@ -539,6 +551,7 @@ public class DebuggerSession implements AbstractDebuggerSession { debuggerContext.setPositionCache(position); DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + @Override public void run() { getContextManager().setState(debuggerContext, STATE_PAUSED, EVENT_PAUSE, null); } @@ -562,9 +575,11 @@ public class DebuggerSession implements AbstractDebuggerSession { } + @Override public void resumed(final SuspendContextImpl suspendContext) { final SuspendContextImpl currentContext = getProcess().getSuspendManager().getPausedContext(); DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + @Override public void run() { if (currentContext != null) { getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, currentContext), STATE_PAUSED, EVENT_CONTEXT, null); @@ -576,6 +591,7 @@ public class DebuggerSession implements AbstractDebuggerSession { }); } + @Override public void processAttached(final DebugProcessImpl process) { final RemoteConnection connection = getProcess().getConnection(); final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection); @@ -584,14 +600,17 @@ public class DebuggerSession implements AbstractDebuggerSession { process.getExecutionResult().getProcessHandler().notifyTextAvailable(message + "\n", ProcessOutputTypes.SYSTEM); DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + @Override public void run() { getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_RUNNING, EVENT_ATTACHED, message); } }); } + @Override public void attachException(final RunProfileState state, final ExecutionException exception, final RemoteConnection remoteConnection) { DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + @Override public void run() { String message = ""; if (state instanceof RemoteState) { @@ -603,6 +622,7 @@ public class DebuggerSession implements AbstractDebuggerSession { }); } + @Override public void processDetached(final DebugProcessImpl debugProcess, boolean closedByUser) { if (!closedByUser) { ExecutionResult executionResult = debugProcess.getExecutionResult(); @@ -614,6 +634,7 @@ public class DebuggerSession implements AbstractDebuggerSession { } } DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + @Override public void run() { final RemoteConnection connection = getProcess().getConnection(); final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection); @@ -624,10 +645,12 @@ public class DebuggerSession implements AbstractDebuggerSession { mySteppingThroughThreads.clear(); } + @Override public void threadStarted(DebugProcess proc, ThreadReference thread) { notifyThreadsRefresh(); } + @Override public void threadStopped(DebugProcess proc, ThreadReference thread) { notifyThreadsRefresh(); } @@ -636,6 +659,7 @@ public class DebuggerSession implements AbstractDebuggerSession { if (!myUpdateAlarm.isDisposed()) { myUpdateAlarm.cancelAllRequests(); myUpdateAlarm.addRequest(new Runnable() { + @Override public void run() { final DebuggerStateManager contextManager = getContextManager(); contextManager.fireStateChanged(contextManager.getContext(), EVENT_THREADS_REFRESH); @@ -646,13 +670,16 @@ public class DebuggerSession implements AbstractDebuggerSession { } private class MyEvaluationListener implements EvaluationListener { + @Override public void evaluationStarted(SuspendContextImpl context) { myIsEvaluating = true; } + @Override public void evaluationFinished(final SuspendContextImpl context) { myIsEvaluating = false; DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + @Override public void run() { if (context != getSuspendContext()) { getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, context), STATE_PAUSED, EVENT_REFRESH, null); diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java index 4ff1adcabda4..5fed47929af3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java @@ -70,7 +70,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { clearCaches(); } catch (InternalException e) { - if (e.errorCode() == 23 /*INVALID_METHODID accoeding to JDI sources*/) { + if (e.errorCode() == 23 /*INVALID_METHODID according to JDI sources*/) { myIsObsolete = Boolean.TRUE; return true; } @@ -83,6 +83,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { return false; } + @Override protected void clearCaches() { DebuggerManagerThreadImpl.assertIsManagerThread(); if (LOG.isDebugEnabled()) { @@ -100,6 +101,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { * Use with caution. Better access stackframe data through the Proxy's methods */ + @Override public StackFrame getStackFrame() throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); @@ -113,7 +115,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { catch (IndexOutOfBoundsException e) { throw new EvaluateException(e.getMessage(), e); } - catch (ObjectCollectedException e) { + catch (ObjectCollectedException ignored) { throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.thread.collected")); } catch (IncompatibleThreadStateException e) { @@ -124,6 +126,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { return myStackFrame; } + @Override public int getFrameIndex() throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); checkValid(); @@ -151,10 +154,13 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { // return false; // } + @Override public VirtualMachineProxyImpl getVirtualMachine() { return (VirtualMachineProxyImpl) myTimer; } + @Nullable + @Override public Location location() throws EvaluateException { InvalidStackFrameException error = null; for (int attempt = 0; attempt < 2; attempt++) { @@ -172,6 +178,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { return null; } + @Override public ThreadReferenceProxyImpl threadProxy() { return myThreadProxy; } @@ -197,13 +204,13 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { } break; } - catch (InvalidStackFrameException e) { + catch (InvalidStackFrameException ignored) { clearCaches(); } } } catch (InternalException e) { - // supress some internal errors caused by bugs in specific JDI implementations + // suppress some internal errors caused by bugs in specific JDI implementations if(e.errorCode() != 23) { throw EvaluateExceptionUtil.createEvaluateException(e); } @@ -238,6 +245,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { return Collections.emptyList(); } + @Override public LocalVariableProxyImpl visibleVariableByName(String name) throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); final LocalVariable variable = visibleVariableByNameInt(name); @@ -332,7 +340,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { myAllValues.put(variable, value); } } - catch (InconsistentDebugInfoException e) { + catch (InconsistentDebugInfoException ignored) { clearCaches(); throw EvaluateExceptionUtil.INCONSISTEND_DEBUG_INFO; } @@ -388,12 +396,13 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { try { return var.getVariable().isVisible(getStackFrame()); } - catch (IllegalArgumentException e) { + catch (IllegalArgumentException ignored) { // can be thrown if frame's method is different than variable's method return false; } } + @Override public ClassLoaderReference getClassLoader() throws EvaluateException { if(myClassLoader == null) { myClassLoader = location().declaringType().classLoader(); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java index 5eb71c30e869..1395654a06d1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java @@ -73,8 +73,6 @@ public abstract class DebuggerEditorImpl extends CompletionEditor{ private final JLabel myChooseFactory = new JLabel(); private WeakReference<ListPopup> myPopup; - private boolean myExplicitlyChosen = false; - private final PsiTreeChangeListener myPsiListener = new PsiTreeChangeAdapter() { public void childRemoved(@NotNull PsiTreeChangeEvent event) { checkContext(); @@ -142,7 +140,6 @@ public abstract class DebuggerEditorImpl extends CompletionEditor{ @Override public void actionPerformed(AnActionEvent e) { setFactory(fragmentFactory); - myExplicitlyChosen = true; setText(getText()); IdeFocusManager.getInstance(getProject()).requestFocus(DebuggerEditorImpl.this, true); } @@ -300,33 +297,12 @@ public abstract class DebuggerEditorImpl extends CompletionEditor{ return DefaultCodeFragmentFactory.getInstance(); } - @NotNull - private CodeFragmentFactory findFactoryForRestore(@NotNull TextWithImports text, @NotNull PsiElement context) { - List<CodeFragmentFactory> factories = DebuggerUtilsEx.getCodeFragmentFactories(context); - - if (myExplicitlyChosen && factories.contains(myFactory)) return myFactory; - - DefaultCodeFragmentFactory defaultFactory = DefaultCodeFragmentFactory.getInstance(); - factories.remove(defaultFactory); - for (CodeFragmentFactory factory : factories) { - if (factory.getFileType().equals(text.getFileType())) { - return factory; - } - } - if (!factories.isEmpty()) return factories.get(0); - else return defaultFactory; - } - protected void restoreFactory(TextWithImports text) { FileType fileType = text.getFileType(); if (fileType == null) return; if (myContext == null) return; - CodeFragmentFactory newFactory = findFactoryForRestore(text, myContext); - if (!newFactory.equals(myFactory)) { - myExplicitlyChosen = false; - setFactory(newFactory); - } + setFactory(findAppropriateFactory(text, myContext)); } private void setFactory(@NotNull final CodeFragmentFactory factory) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java index e021d76b271b..46f1515f1ea5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java @@ -19,19 +19,17 @@ import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.actions.*; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.settings.*; -import com.intellij.debugger.ui.breakpoints.*; +import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.ide.DataManager; import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Key; -import com.intellij.util.containers.ContainerUtil; import com.intellij.xdebugger.AbstractDebuggerSession; import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule; import com.intellij.xdebugger.impl.DebuggerSupport; @@ -45,9 +43,10 @@ import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler; import com.intellij.xdebugger.impl.settings.DebuggerSettingsPanelProvider; import org.jetbrains.annotations.NotNull; +import javax.swing.*; +import java.awt.*; import java.util.ArrayList; import java.util.Collection; -import java.util.List; /** * @author nik @@ -63,8 +62,6 @@ public class JavaDebuggerSupport extends DebuggerSupport { private final ForceRunToCursorActionHandler myForceRunToCursorActionHandler = new ForceRunToCursorActionHandler(); private final ResumeActionHandler myResumeActionHandler = new ResumeActionHandler(); private final PauseActionHandler myPauseActionHandler = new PauseActionHandler(); - private final ToggleLineBreakpointActionHandler myToggleLineBreakpointActionHandler = new ToggleLineBreakpointActionHandler(false); - private final ToggleLineBreakpointActionHandler myToggleTemporaryLineBreakpointActionHandler = new ToggleLineBreakpointActionHandler(true); private final ShowExecutionPointActionHandler myShowExecutionPointActionHandler = new ShowExecutionPointActionHandler(); private final EvaluateActionHandler myEvaluateActionHandler = new EvaluateActionHandler(); private final QuickEvaluateActionHandler myQuickEvaluateHandler = new QuickEvaluateActionHandler(); @@ -73,84 +70,98 @@ public class JavaDebuggerSupport extends DebuggerSupport { private final DebuggerActionHandler mySmartStepIntoHandler = new JvmSmartStepIntoActionHandler(); private final DebuggerActionHandler myAddToWatchedActionHandler = new AddToWatchActionHandler(); private final JavaMarkObjectActionHandler myMarkObjectActionHandler = new JavaMarkObjectActionHandler(); - private final JavaEditBreakpointActionHandler myEditBreakpointActionHandler = new JavaEditBreakpointActionHandler(); + @Override @NotNull public BreakpointPanelProvider<?> getBreakpointPanelProvider() { return myBreakpointPanelProvider; } + @Override @NotNull public DebuggerActionHandler getStepOverHandler() { return myStepOverActionHandler; } + @Override @NotNull public DebuggerActionHandler getStepIntoHandler() { return myStepIntoActionHandler; } + @Override @NotNull public DebuggerActionHandler getSmartStepIntoHandler() { return mySmartStepIntoHandler; } + @Override @NotNull public DebuggerActionHandler getStepOutHandler() { return myStepOutActionHandler; } + @Override @NotNull public DebuggerActionHandler getForceStepOverHandler() { return myForceStepOverActionHandler; } + @Override @NotNull public DebuggerActionHandler getForceStepIntoHandler() { return myForceStepIntoActionHandler; } + @Override @NotNull public DebuggerActionHandler getRunToCursorHandler() { return myRunToCursorActionHandler; } + @Override @NotNull public DebuggerActionHandler getForceRunToCursorHandler() { return myForceRunToCursorActionHandler; } + @Override @NotNull public DebuggerActionHandler getResumeActionHandler() { return myResumeActionHandler; } + @Override @NotNull public DebuggerActionHandler getPauseHandler() { return myPauseActionHandler; } + @Override @NotNull public DebuggerActionHandler getToggleLineBreakpointHandler() { - return myToggleLineBreakpointActionHandler; + return DISABLED; } @NotNull @Override public DebuggerActionHandler getToggleTemporaryLineBreakpointHandler() { - return myToggleTemporaryLineBreakpointActionHandler; + return DISABLED; } + @Override @NotNull public DebuggerActionHandler getShowExecutionPointHandler() { return myShowExecutionPointActionHandler; } + @Override @NotNull public DebuggerActionHandler getEvaluateHandler() { return myEvaluateActionHandler; } + @Override @NotNull public QuickEvaluateHandler getQuickEvaluateHandler() { return myQuickEvaluateHandler; @@ -162,6 +173,7 @@ public class JavaDebuggerSupport extends DebuggerSupport { return myAddToWatchedActionHandler; } + @Override @NotNull public DebuggerToggleActionHandler getMuteBreakpointsHandler() { return myMuteBreakpointsHandler; @@ -182,134 +194,141 @@ public class JavaDebuggerSupport extends DebuggerSupport { @NotNull @Override public EditBreakpointActionHandler getEditBreakpointAction() { - return myEditBreakpointActionHandler; + return DISABLED_EDIT; } + @Override @NotNull public DebuggerSettingsPanelProvider getSettingsPanelProvider() { return myDebuggerSettingsPanelProvider; } private static class JavaBreakpointPanelProvider extends BreakpointPanelProvider<Breakpoint> { - private final List<MyBreakpointManagerListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); + //private final List<MyBreakpointManagerListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); @Override public AnAction[] getAddBreakpointActions(@NotNull Project project) { - List<AnAction> result = new ArrayList<AnAction>(); - BreakpointFactory[] breakpointFactories = BreakpointFactory.getBreakpointFactories(); - for (BreakpointFactory breakpointFactory : breakpointFactories) { - result.add(new AddJavaBreakpointAction(breakpointFactory)); - } - return result.toArray(new AnAction[result.size()]); + //List<AnAction> result = new ArrayList<AnAction>(); + //BreakpointFactory[] breakpointFactories = BreakpointFactory.getBreakpointFactories(); + //for (BreakpointFactory breakpointFactory : breakpointFactories) { + // result.add(new AddJavaBreakpointAction(breakpointFactory)); + //} + //return result.toArray(new AnAction[result.size()]); + return AnAction.EMPTY_ARRAY; } @Override public void createBreakpointsGroupingRules(Collection<XBreakpointGroupingRule> rules) { - rules.add(new XBreakpointGroupingByCategoryRule()); + //rules.add(new XBreakpointGroupingByCategoryRule()); rules.add(new XBreakpointGroupingByPackageRule()); rules.add(new XBreakpointGroupingByClassRule()); } @Override public void addListener(final BreakpointsListener listener, Project project, Disposable disposable) { - BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager(); - final MyBreakpointManagerListener listener1 = new MyBreakpointManagerListener(listener, breakpointManager); - breakpointManager.addBreakpointManagerListener(listener1); - myListeners.add(listener1); - Disposer.register(disposable, new Disposable() { - @Override - public void dispose() { - removeListener(listener); - } - }); + //BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager(); + //final MyBreakpointManagerListener listener1 = new MyBreakpointManagerListener(listener, breakpointManager); + //breakpointManager.addBreakpointManagerListener(listener1); + //myListeners.add(listener1); + //Disposer.register(disposable, new Disposable() { + // @Override + // public void dispose() { + // removeListener(listener); + // } + //}); } @Override protected void removeListener(BreakpointsListener listener) { - for (MyBreakpointManagerListener managerListener : myListeners) { - if (managerListener.myListener == listener) { - BreakpointManager manager = managerListener.myBreakpointManager; - manager.removeBreakpointManagerListener(managerListener); - myListeners.remove(managerListener); - break; - } - } + //for (MyBreakpointManagerListener managerListener : myListeners) { + // if (managerListener.myListener == listener) { + // BreakpointManager manager = managerListener.myBreakpointManager; + // manager.removeBreakpointManagerListener(managerListener); + // myListeners.remove(managerListener); + // break; + // } + //} } + @Override public int getPriority() { - return 1; + return 100; } + @Override public Breakpoint findBreakpoint(@NotNull final Project project, @NotNull final Document document, final int offset) { - return DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().findBreakpoint(document, offset, null); + return null; + //return DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().findBreakpoint(document, offset, null); } @Override public GutterIconRenderer getBreakpointGutterIconRenderer(Object breakpoint) { - if (breakpoint instanceof BreakpointWithHighlighter) { - final RangeHighlighter highlighter = ((BreakpointWithHighlighter)breakpoint).getHighlighter(); - if (highlighter != null) { - return (GutterIconRenderer)highlighter.getGutterIconRenderer(); - } - } + //if (breakpoint instanceof BreakpointWithHighlighter) { + // final RangeHighlighter highlighter = ((BreakpointWithHighlighter)breakpoint).getHighlighter(); + // if (highlighter != null) { + // return (GutterIconRenderer)highlighter.getGutterIconRenderer(); + // } + //} return null; } + @Override public void onDialogClosed(final Project project) { - DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().updateAllRequests(); + //DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().updateAllRequests(); } @Override public void provideBreakpointItems(Project project, Collection<BreakpointItem> items) { - for (BreakpointFactory breakpointFactory : BreakpointFactory.getBreakpointFactories()) { - Key<? extends Breakpoint> category = breakpointFactory.getBreakpointCategory(); - Breakpoint[] breakpoints = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getBreakpoints(category); - for (Breakpoint breakpoint : breakpoints) { - items.add(breakpointFactory.createBreakpointItem(breakpoint)); - } - } + //for (BreakpointFactory breakpointFactory : BreakpointFactory.getBreakpointFactories()) { + // Key<? extends Breakpoint> category = breakpointFactory.getBreakpointCategory(); + // Breakpoint[] breakpoints = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getBreakpoints(category); + // for (Breakpoint breakpoint : breakpoints) { + // items.add(breakpointFactory.createBreakpointItem(breakpoint)); + // } + //} } - private static class AddJavaBreakpointAction extends AnAction { - private BreakpointFactory myBreakpointFactory; - - public AddJavaBreakpointAction(BreakpointFactory breakpointFactory) { - myBreakpointFactory = breakpointFactory; - Presentation p = getTemplatePresentation(); - p.setIcon(myBreakpointFactory.getIcon()); - p.setText(breakpointFactory.getDisplayName()); - } - - @Override - public void update(AnActionEvent e) { - e.getPresentation().setVisible(myBreakpointFactory.canAddBreakpoints()); - } - - @Override - public void actionPerformed(AnActionEvent e) { - myBreakpointFactory.addBreakpoint(getEventProject(e)); - } - } - - private static class MyBreakpointManagerListener implements BreakpointManagerListener { - - private final BreakpointsListener myListener; - public BreakpointManager myBreakpointManager; - - - public MyBreakpointManagerListener(BreakpointsListener listener, BreakpointManager breakpointManager) { - myListener = listener; - myBreakpointManager = breakpointManager; - } - - @Override - public void breakpointsChanged() { - myListener.breakpointsChanged(); - } - } + //private static class AddJavaBreakpointAction extends AnAction { + // private BreakpointFactory myBreakpointFactory; + // + // public AddJavaBreakpointAction(BreakpointFactory breakpointFactory) { + // myBreakpointFactory = breakpointFactory; + // Presentation p = getTemplatePresentation(); + // p.setIcon(myBreakpointFactory.getIcon()); + // p.setText(breakpointFactory.getDisplayName()); + // } + // + // @Override + // public void update(AnActionEvent e) { + // e.getPresentation().setVisible(myBreakpointFactory.canAddBreakpoints()); + // } + // + // @Override + // public void actionPerformed(AnActionEvent e) { + // myBreakpointFactory.addBreakpoint(getEventProject(e)); + // } + //} + + //private static class MyBreakpointManagerListener implements BreakpointManagerListener { + // + // private final BreakpointsListener myListener; + // public BreakpointManager myBreakpointManager; + // + // + // public MyBreakpointManagerListener(BreakpointsListener listener, BreakpointManager breakpointManager) { + // myListener = listener; + // myBreakpointManager = breakpointManager; + // } + // + // @Override + // public void breakpointsChanged() { + // myListener.breakpointsChanged(); + // } + //} } public static class JavaDebuggerSettingsPanelProvider extends DebuggerSettingsPanelProvider { + @Override public int getPriority() { return 1; } @@ -319,6 +338,7 @@ public class JavaDebuggerSupport extends DebuggerSupport { return new DebuggerLaunchingConfigurable(); } + @Override public Collection<? extends Configurable> getConfigurables() { final ArrayList<Configurable> configurables = new ArrayList<Configurable>(); configurables.add(new DebuggerDataViewsConfigurable(null)); @@ -328,6 +348,7 @@ public class JavaDebuggerSupport extends DebuggerSupport { return configurables; } + @Override public void apply() { NodeRendererSettings.getInstance().fireRenderersChanged(); } @@ -341,4 +362,27 @@ public class JavaDebuggerSupport extends DebuggerSupport { } return ProjectManager.getInstance().getDefaultProject(); } + + private static final DebuggerActionHandler DISABLED = new DebuggerActionHandler() { + @Override + public void perform(@NotNull Project project, AnActionEvent event) { + } + + @Override + public boolean isEnabled(@NotNull Project project, AnActionEvent event) { + return false; + } + }; + + private static final EditBreakpointActionHandler DISABLED_EDIT = new EditBreakpointActionHandler() { + @Override + protected void doShowPopup(Project project, JComponent component, Point whereToShow, Object breakpoint) { + + } + + @Override + public boolean isEnabled(@NotNull Project project, AnActionEvent event) { + return false; + } + }; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/PositionHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/PositionHighlighter.java index e5bb8faafb61..dd0b0de43151 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/PositionHighlighter.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/PositionHighlighter.java @@ -437,7 +437,7 @@ public class PositionHighlighter { public void actionPerformed(AnActionEvent e) { if (myEventsOutOfLine.size() == 1) { Breakpoint breakpoint = myEventsOutOfLine.get(0).getFirst(); - breakpoint.ENABLED = !breakpoint.ENABLED; + breakpoint.setEnabled(!breakpoint.isEnabled()); DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().fireBreakpointChanged(breakpoint); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointCategoryGroup.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointCategoryGroup.java deleted file mode 100644 index 032b480c5584..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointCategoryGroup.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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.debugger.ui; - -import com.intellij.debugger.ui.breakpoints.Breakpoint; -import com.intellij.debugger.ui.breakpoints.BreakpointFactory; -import com.intellij.openapi.util.Key; -import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroup; -import com.intellij.xdebugger.impl.breakpoints.ui.grouping.XBreakpointTypeGroup; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -/** - * Created with IntelliJ IDEA. - * User: zajac - * Date: 23.05.12 - * Time: 16:22 - * To change this template use File | Settings | File Templates. - */ -public class XBreakpointCategoryGroup extends XBreakpointGroup { - private Key<? extends Breakpoint> myCategory; - private Icon myIcon; - private final String myName; - - public XBreakpointCategoryGroup(BreakpointFactory factory) { - myCategory = factory.getBreakpointCategory(); - myIcon = factory.getIcon(); - final String name = factory.getDisplayName(); - myName = name != null ? name : "UNKNOWN"; - } - - public Key<? extends Breakpoint> getCategory() { - return myCategory; - } - - @Override - public Icon getIcon(boolean isOpen) { - return myIcon; - } - - @NotNull - @Override - public String getName() { - return myName; - } - - @Override - public int compareTo(XBreakpointGroup o) { - if (o instanceof XBreakpointTypeGroup) { - return -1; - } - if (o instanceof XBreakpointCategoryGroup) { - return getFactoryIndex() - ((XBreakpointCategoryGroup)o).getFactoryIndex(); - } - return super.compareTo(o); - } - - private int getFactoryIndex() { - BreakpointFactory[] breakpointFactories = BreakpointFactory.getBreakpointFactories(); - for (int i = 0; i < breakpointFactories.length; ++i) { - if (breakpointFactories[i].getBreakpointCategory().equals(myCategory)) { - return i; - } - } - return -1; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByCategoryRule.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByCategoryRule.java deleted file mode 100644 index f9dc88af07ac..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByCategoryRule.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.debugger.ui; - -import com.intellij.debugger.ui.breakpoints.AnyExceptionBreakpoint; -import com.intellij.debugger.ui.breakpoints.Breakpoint; -import com.intellij.debugger.ui.breakpoints.BreakpointFactory; -import com.intellij.debugger.ui.breakpoints.ExceptionBreakpoint; -import com.intellij.openapi.util.Key; -import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule; -import com.intellij.xdebugger.breakpoints.ui.XBreakpointsGroupingPriorities; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -class XBreakpointGroupingByCategoryRule<B> extends XBreakpointGroupingRule<B, XBreakpointCategoryGroup> { - XBreakpointGroupingByCategoryRule() { - super("XBreakpointGroupingByCategoryRule", "Type"); - } - - @Override - public boolean isAlwaysEnabled() { - return true; - } - - @Override - public int getPriority() { - return XBreakpointsGroupingPriorities.BY_TYPE; - } - - @Override - public XBreakpointCategoryGroup getGroup(@NotNull B b, @NotNull Collection<XBreakpointCategoryGroup> groups) { - if (b instanceof Breakpoint) { - final Breakpoint breakpoint = (Breakpoint)b; - Key<? extends Breakpoint> category = breakpoint.getCategory(); - if (category.equals(AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT)) { - category = ExceptionBreakpoint.CATEGORY; - } - for (XBreakpointCategoryGroup group : groups) { - if (group.getCategory().equals(category)) { - return group; - } - } - final BreakpointFactory factory = BreakpointFactory.getInstance(category); - if (factory != null) { - return new XBreakpointCategoryGroup(factory); - } - } - return null; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByClassRule.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByClassRule.java index f06a17ef0727..cebaf68612a0 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByClassRule.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByClassRule.java @@ -15,8 +15,11 @@ */ package com.intellij.debugger.ui; +import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.ui.breakpoints.Breakpoint; +import com.intellij.debugger.ui.breakpoints.BreakpointManager; import com.intellij.icons.AllIcons; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule; import com.intellij.xdebugger.breakpoints.ui.XBreakpointsGroupingPriorities; import org.jetbrains.annotations.NotNull; @@ -42,10 +45,14 @@ class XBreakpointGroupingByClassRule<B> extends XBreakpointGroupingRule<B, XBrea @Override public XBreakpointClassGroup getGroup(@NotNull B b, @NotNull Collection<XBreakpointClassGroup> groups) { - if (b instanceof Breakpoint) { - final Breakpoint breakpoint = (Breakpoint)b; - String className = breakpoint.getShortClassName(); - String packageName = breakpoint.getPackageName(); + if (b instanceof XBreakpoint) { + BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(JavaDebuggerSupport.getCurrentProject()).getBreakpointManager(); + Breakpoint javaBreakpoint = breakpointManager.findBreakpoint((XBreakpoint)b); + if (javaBreakpoint == null) { + return null; + } + String className = javaBreakpoint.getShortClassName(); + String packageName = javaBreakpoint.getPackageName(); if (className == null) { return null; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java index 5763a3648f64..98ef5a3409ec 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java @@ -15,10 +15,12 @@ */ package com.intellij.debugger.ui; -import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter; -import com.intellij.debugger.ui.breakpoints.ExceptionBreakpoint; +import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.ui.breakpoints.Breakpoint; +import com.intellij.debugger.ui.breakpoints.BreakpointManager; import com.intellij.icons.AllIcons; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule; import com.intellij.xdebugger.breakpoints.ui.XBreakpointsGroupingPriorities; import org.jetbrains.annotations.NotNull; @@ -41,11 +43,12 @@ public class XBreakpointGroupingByPackageRule<B> extends XBreakpointGroupingRule @Override public XBreakpointPackageGroup getGroup(@NotNull B breakpoint, @NotNull Collection<XBreakpointPackageGroup> groups) { String packageName = null; - if (breakpoint instanceof BreakpointWithHighlighter) { - packageName = ((BreakpointWithHighlighter)breakpoint).getPackageName(); - } - else if (breakpoint instanceof ExceptionBreakpoint) { - packageName = ((ExceptionBreakpoint)breakpoint).getPackageName(); + if (breakpoint instanceof XBreakpoint) { + BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(JavaDebuggerSupport.getCurrentProject()).getBreakpointManager(); + Breakpoint javaBreakpoint = breakpointManager.findBreakpoint((XBreakpoint)breakpoint); + if (javaBreakpoint != null) { + packageName = javaBreakpoint.getPackageName(); + } } if (packageName == null) { return null; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.java index f325da10fcde..e3cd5229e0ab 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.java @@ -41,7 +41,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; -abstract class AddFieldBreakpointDialog extends DialogWrapper { +public abstract class AddFieldBreakpointDialog extends DialogWrapper { private final Project myProject; private JPanel myPanel; private TextFieldWithBrowseButton myFieldChooser; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointDialog.java index c18acb715935..73c74a4eed0a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointDialog.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointDialog.java @@ -30,7 +30,7 @@ public class AddWildcardBreakpointDialog extends DialogWrapper { private JTextField myClassPatternField; private JTextField myMethodNameField; - protected AddWildcardBreakpointDialog(Project project) { + public AddWildcardBreakpointDialog(Project project) { super(project, true); setTitle("Add Method Breakpoint"); init(); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java index 3d1ff8507d10..8787290c2f09 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java @@ -27,6 +27,7 @@ import com.intellij.debugger.engine.DebuggerManagerThreadImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.Key; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.sun.jdi.ReferenceType; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -34,9 +35,9 @@ import org.jetbrains.annotations.NonNls; public class AnyExceptionBreakpoint extends ExceptionBreakpoint { public static final @NonNls Key<AnyExceptionBreakpoint> ANY_EXCEPTION_BREAKPOINT = BreakpointCategory.lookup("breakpoint_any"); - protected AnyExceptionBreakpoint(Project project) { - super(project, null, null); - ENABLED = false; + protected AnyExceptionBreakpoint(Project project, XBreakpoint xBreakpoint) { + super(project, null, null, xBreakpoint); + //setEnabled(false); } public Key<AnyExceptionBreakpoint> getCategory() { @@ -49,7 +50,7 @@ public class AnyExceptionBreakpoint extends ExceptionBreakpoint { public void createRequest(DebugProcessImpl debugProcess) { DebuggerManagerThreadImpl.assertIsManagerThread(); - if (!ENABLED || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { + if (!isEnabled() || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { return; } super.processClassPrepare(debugProcess, null); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java deleted file mode 100644 index f595c1d81c65..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.ui.breakpoints; - -import com.intellij.icons.AllIcons; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import org.jdom.Element; - -import javax.swing.*; - -/** - * @author Eugene Zhuravlev - * Date: Apr 26, 2005 - */ -public class AnyExceptionBreakpointFactory extends BreakpointFactory{ - public Breakpoint createBreakpoint(Project project, final Element element) { - return new AnyExceptionBreakpoint(project); - } - - public Icon getIcon() { - return AllIcons.Debugger.Db_exception_breakpoint; - } - - public Icon getDisabledIcon() { - return AllIcons.Debugger.Db_disabled_exception_breakpoint; - } - - @Override - protected String getHelpID() { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - @Override - public String getDisplayName() { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - @Override - public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) { - return new ExceptionBreakpointPropertiesPanel(project, compact); - } - - @Override - public boolean breakpointCanBeRemoved(Breakpoint breakpoint) { - return false; - } - - public Key<AnyExceptionBreakpoint> getBreakpointCategory() { - return AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java index 1b370ca47ded..bbbcf8ef1265 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java @@ -30,45 +30,62 @@ import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.debugger.requests.ClassPrepareRequestor; +import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.ui.AppUIUtil; +import com.intellij.ui.classFilter.ClassFilter; import com.intellij.util.StringBuilderSpinAllocator; -import com.sun.jdi.ObjectReference; -import com.sun.jdi.ReferenceType; -import com.sun.jdi.Value; -import com.sun.jdi.VoidValue; +import com.intellij.xdebugger.breakpoints.SuspendPolicy; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.sun.jdi.*; import com.sun.jdi.event.LocatableEvent; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; import javax.swing.*; import java.util.List; -public abstract class Breakpoint extends FilteredRequestor implements ClassPrepareRequestor { - public boolean ENABLED = true; - public boolean LOG_ENABLED = false; - public boolean LOG_EXPRESSION_ENABLED = false; - public boolean REMOVE_AFTER_HIT = false; - private TextWithImports myLogMessage; // an expression to be evaluated and printed +public abstract class Breakpoint<P extends JavaBreakpointProperties> implements FilteredRequestor, ClassPrepareRequestor { + final XBreakpoint<P> myXBreakpoint; + protected final Project myProject; + + //private boolean ENABLED = true; + //private boolean LOG_ENABLED = false; + //private boolean LOG_EXPRESSION_ENABLED = false; + //private boolean REMOVE_AFTER_HIT = false; + //private TextWithImports myLogMessage; // an expression to be evaluated and printed @NonNls private static final String LOG_MESSAGE_OPTION_NAME = "LOG_MESSAGE"; public static final Breakpoint[] EMPTY_ARRAY = new Breakpoint[0]; protected boolean myCachedVerifiedState = false; + //private TextWithImportsImpl myLogMessage; - protected Breakpoint(@NotNull Project project) { - super(project); - myLogMessage = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""); + protected Breakpoint(@NotNull Project project, XBreakpoint<P> xBreakpoint) { + //super(project); + myProject = project; + myXBreakpoint = xBreakpoint; + //myLogMessage = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""); //noinspection AbstractMethodCallInConstructor - final BreakpointDefaults defaults = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getBreakpointDefaults(getCategory()); - SUSPEND_POLICY = defaults.getSuspendPolicy(); - CONDITION_ENABLED = defaults.isConditionEnabled(); + //final BreakpointDefaults defaults = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getBreakpointDefaults(getCategory()); + //SUSPEND_POLICY = defaults.getSuspendPolicy(); + //CONDITION_ENABLED = defaults.isConditionEnabled(); + } + + public Project getProject() { + return myProject; + } + + protected P getProperties() { + return myXBreakpoint.getProperties(); } public abstract PsiClass getPsiClass(); @@ -100,6 +117,16 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa myCachedVerifiedState = isVerified; } + public boolean isRemoveAfterHit() { + return myXBreakpoint instanceof XLineBreakpoint && ((XLineBreakpoint)myXBreakpoint).isTemporary(); + } + + public void setRemoveAfterHit(boolean value) { + if (myXBreakpoint instanceof XLineBreakpoint) { + ((XLineBreakpoint)myXBreakpoint).setTemporary(value); + } + } + @Nullable public String getShortClassName() { final String className = getClassName(); @@ -210,19 +237,19 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa private void runAction(final EvaluationContextImpl context, LocatableEvent event) { final DebugProcessImpl debugProcess = context.getDebugProcess(); - if (LOG_ENABLED || LOG_EXPRESSION_ENABLED) { + if (isLogEnabled() || isLogExpressionEnabled()) { final StringBuilder buf = StringBuilderSpinAllocator.alloc(); try { - if (LOG_ENABLED) { + if (myXBreakpoint.isLogMessage()) { buf.append(getEventMessage(event)); buf.append("\n"); } - final TextWithImports expressionToEvaluate = getLogMessage(); - if (LOG_EXPRESSION_ENABLED && expressionToEvaluate != null && !"".equals(expressionToEvaluate.getText())) { + if (isLogExpressionEnabled()) { if(!debugProcess.isAttached()) { return; } - + + final TextWithImports expressionToEvaluate = getLogMessage(); try { ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(getProject(), new EvaluatingComputable<ExpressionEvaluator>() { @Override @@ -252,11 +279,112 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa StringBuilderSpinAllocator.dispose(buf); } } - if (REMOVE_AFTER_HIT) { + if (isRemoveAfterHit()) { handleTemporaryBreakpointHit(debugProcess); } } + /** + * @return true if the ID was added or false otherwise + */ + private boolean hasObjectID(long id) { + for (InstanceFilter instanceFilter : getInstanceFilters()) { + if (instanceFilter.getId() == id) { + return true; + } + } + return false; + } + + public boolean evaluateCondition(final EvaluationContextImpl context, LocatableEvent event) throws EvaluateException { + if(isCountFilterEnabled()) { + final DebugProcessImpl debugProcess = context.getDebugProcess(); + debugProcess.getVirtualMachineProxy().suspend(); + debugProcess.getRequestsManager().deleteRequest(this); + ((Breakpoint)this).createRequest(debugProcess); + debugProcess.getVirtualMachineProxy().resume(); + } + if (isInstanceFiltersEnabled()) { + Value value = context.getThisObject(); + if (value != null) { // non-static + ObjectReference reference = (ObjectReference)value; + if(!hasObjectID(reference.uniqueID())) { + return false; + } + } + } + + if (isClassFiltersEnabled()) { + String typeName = calculateEventClass(context, event); + if (!typeMatchesClassFilters(typeName)) return false; + } + + if (isConditionEnabled() && !getCondition().getText().isEmpty()) { + try { + ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(context.getProject(), new EvaluatingComputable<ExpressionEvaluator>() { + public ExpressionEvaluator compute() throws EvaluateException { + final SourcePosition contextSourcePosition = ContextUtil.getSourcePosition(context); + // IMPORTANT: calculate context psi element basing on the location where the exception + // has been hit, not on the location where it was set. (For line breakpoints these locations are the same, however, + // for method, exception and field breakpoints these locations differ) + PsiElement contextPsiElement = ContextUtil.getContextElement(contextSourcePosition); + if (contextPsiElement == null) { + contextPsiElement = getEvaluationElement(); // as a last resort + } + return EvaluatorBuilderImpl.build(getCondition(), contextPsiElement, contextSourcePosition); + } + }); + final Value value = evaluator.evaluate(context); + if (!(value instanceof BooleanValue)) { + throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected")); + } + if(!((BooleanValue)value).booleanValue()) { + return false; + } + } + catch (EvaluateException ex) { + if(ex.getCause() instanceof VMDisconnectedException) { + return false; + } + throw EvaluateExceptionUtil.createEvaluateException( + DebuggerBundle.message("error.failed.evaluating.breakpoint.condition", getCondition(), ex.getMessage()) + ); + } + return true; + } + + return true; + } + + protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException { + return event.location().declaringType().name(); + } + + private boolean typeMatchesClassFilters(@Nullable String typeName) { + if (typeName == null) { + return true; + } + boolean matches = false, hasEnabled = false; + for (ClassFilter classFilter : getClassFilters()) { + if (classFilter.isEnabled()) { + hasEnabled = true; + if (classFilter.matches(typeName)) { + matches = true; + break; + } + } + } + if(hasEnabled && !matches) { + return false; + } + for (ClassFilter classFilter : getClassExclusionFilters()) { + if (classFilter.isEnabled() && classFilter.matches(typeName)) { + return false; + } + } + return true; + } + private void handleTemporaryBreakpointHit(final DebugProcessImpl debugProcess) { debugProcess.addDebugProcessListener(new DebugProcessAdapter() { @Override @@ -288,26 +416,213 @@ public abstract class Breakpoint extends FilteredRequestor implements ClassPrepa RequestManagerImpl.deleteRequests(this); } - @Override public void readExternal(Element parentNode) throws InvalidDataException { - super.readExternal(parentNode); - String logMessage = JDOMExternalizerUtil.readField(parentNode, LOG_MESSAGE_OPTION_NAME); - if (logMessage != null) { - setLogMessage(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, logMessage)); + FilteredRequestorImpl requestor = new FilteredRequestorImpl(myProject); + requestor.readTo(parentNode, this); + try { + setEnabled(Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "ENABLED"))); + } catch (Exception e) { } + try { + setLogEnabled(Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "LOG_ENABLED"))); + } catch (Exception e) { + } + try { + if (Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "LOG_EXPRESSION_ENABLED"))) { + String logMessage = JDOMExternalizerUtil.readField(parentNode, LOG_MESSAGE_OPTION_NAME); + if (logMessage != null) { + setLogMessage(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, logMessage)); + } + } + } catch (Exception e) { + } + try { + setRemoveAfterHit(Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "REMOVE_AFTER_HIT"))); + } catch (Exception e) { + } + } + + //@Override + //public void writeExternal(Element parentNode) throws WriteExternalException { + //super.writeExternal(parentNode); + //JDOMExternalizerUtil.writeField(parentNode, LOG_MESSAGE_OPTION_NAME, getLogMessage().toExternalForm()); + //} + + //public void setLogMessage(TextWithImports logMessage) { + // myLogMessage = logMessage; + //} + + public abstract PsiElement getEvaluationElement(); + + protected TextWithImports getLogMessage() { + return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, myXBreakpoint.getLogExpression()); + } + + protected TextWithImports getCondition() { + return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, myXBreakpoint.getCondition()); + } + + public boolean isEnabled() { + return myXBreakpoint.isEnabled(); + } + + public void setEnabled(boolean enabled) { + myXBreakpoint.setEnabled(enabled); + } + + protected boolean isLogEnabled() { + return myXBreakpoint.isLogMessage(); + } + + public void setLogEnabled(boolean logEnabled) { + myXBreakpoint.setLogMessage(logEnabled); + } + + protected boolean isLogExpressionEnabled() { + String expression = myXBreakpoint.getLogExpression(); + if (expression == null || expression.isEmpty()) { + return false; + } + return !getLogMessage().isEmpty(); + } + + @Override + public boolean isCountFilterEnabled() { + if (getProperties() == null) { + return false; + } + return getProperties().COUNT_FILTER_ENABLED; + } + public void setCountFilterEnabled(boolean enabled) { + getProperties().COUNT_FILTER_ENABLED = enabled; + } + + @Override + public int getCountFilter() { + return getProperties().COUNT_FILTER; + } + + public void setCountFilter(int filter) { + getProperties().COUNT_FILTER = filter; + } + + @Override + public boolean isClassFiltersEnabled() { + if (getProperties() == null) { + return false; + } + return getProperties().CLASS_FILTERS_ENABLED; + } + + public void setClassFiltersEnabled(boolean enabled) { + getProperties().CLASS_FILTERS_ENABLED = enabled; + } + + @Override + public ClassFilter[] getClassFilters() { + return getProperties().getClassFilters(); + } + + public void setClassFilters(ClassFilter[] filters) { + getProperties().setClassFilters(filters); + } + + @Override + public ClassFilter[] getClassExclusionFilters() { + return getProperties().getClassExclusionFilters(); + } + + protected void setClassExclusionFilters(ClassFilter[] filters) { + getProperties().setClassExclusionFilters(filters); + } + + @Override + public boolean isInstanceFiltersEnabled() { + if (getProperties() == null) { + return false; + } + return getProperties().INSTANCE_FILTERS_ENABLED; + } + + public void setInstanceFiltersEnabled(boolean enabled) { + getProperties().INSTANCE_FILTERS_ENABLED = enabled; } @Override - public void writeExternal(Element parentNode) throws WriteExternalException { - super.writeExternal(parentNode); - JDOMExternalizerUtil.writeField(parentNode, LOG_MESSAGE_OPTION_NAME, getLogMessage().toExternalForm()); + public InstanceFilter[] getInstanceFilters() { + return getProperties().getInstanceFilters(); + } + + public void setInstanceFilters(InstanceFilter[] filters) { + getProperties().setInstanceFilters(filters); + } + + private static String getSuspendPolicy(XBreakpoint breakpoint) { + switch (breakpoint.getSuspendPolicy()) { + case ALL: + return DebuggerSettings.SUSPEND_ALL; + case THREAD: + return DebuggerSettings.SUSPEND_THREAD; + case NONE: + return DebuggerSettings.SUSPEND_NONE; + + default: + throw new IllegalArgumentException("unknown suspend policy"); + } + } + + static SuspendPolicy transformSuspendPolicy(String policy) { + if (DebuggerSettings.SUSPEND_ALL.equals(policy)) { + return SuspendPolicy.ALL; + } else if (DebuggerSettings.SUSPEND_THREAD.equals(policy)) { + return SuspendPolicy.THREAD; + } else if (DebuggerSettings.SUSPEND_NONE.equals(policy)) { + return SuspendPolicy.NONE; + } else { + throw new IllegalArgumentException("unknown suspend policy"); + } } - public TextWithImports getLogMessage() { - return myLogMessage; + protected boolean isSuspend() { + return myXBreakpoint.getSuspendPolicy() != SuspendPolicy.NONE; + } + + @Override + public String getSuspendPolicy() { + return getSuspendPolicy(myXBreakpoint); + } + + public void setSuspendPolicy(String policy) { + myXBreakpoint.setSuspendPolicy(transformSuspendPolicy(policy)); + } + + protected void setLogMessage(@Nullable TextWithImports logMessage) { + if (logMessage != null && !logMessage.getText().isEmpty()) { + myXBreakpoint.setLogExpression(logMessage.toExternalForm()); + } + else { + myXBreakpoint.setLogExpression(null); + } + } + + protected boolean isConditionEnabled() { + String condition = myXBreakpoint.getCondition(); + if (condition == null || condition.isEmpty()) { + return false; + } + return !getCondition().isEmpty(); + } + + public void setCondition(@Nullable TextWithImports condition) { + if (condition != null && !condition.getText().isEmpty()) { + myXBreakpoint.setCondition(condition.toExternalForm()); + } + else { + myXBreakpoint.setCondition(null); + } } - public void setLogMessage(TextWithImports logMessage) { - myLogMessage = logMessage; + protected void addInstanceFilter(long l) { + getProperties().addInstanceFilter(l); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java deleted file mode 100644 index 67c32935849e..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.ui.breakpoints; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem; -import org.jdom.Element; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -/** - * Used to deexternalize breakpoints of certain category while reading saved configuration and for creating configuration UI - */ -public abstract class BreakpointFactory { - public static final ExtensionPointName<BreakpointFactory> EXTENSION_POINT_NAME = - ExtensionPointName.create("com.intellij.debugger.breakpointFactory"); - - public static BreakpointFactory[] getBreakpointFactories() { - return ApplicationManager.getApplication().getExtensions(EXTENSION_POINT_NAME); - } - - public abstract Breakpoint createBreakpoint(Project project, final Element element); - - public abstract Key<? extends Breakpoint> getBreakpointCategory(); - - public abstract Icon getIcon(); - - public abstract Icon getDisabledIcon(); - - @Nullable - public static BreakpointFactory getInstance(Key<? extends Breakpoint> category) { - final BreakpointFactory[] allFactories = getBreakpointFactories(); - for (final BreakpointFactory factory : allFactories) { - if (category.equals(factory.getBreakpointCategory())) { - return factory; - } - } - return null; - } - - protected abstract String getHelpID(); - - public abstract String getDisplayName(); - - @Nullable - public abstract BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact); - - @Nullable - public Breakpoint addBreakpoint(Project project) { - return null; - } - - public boolean canAddBreakpoints() { - return false; - } - - public boolean breakpointCanBeRemoved(Breakpoint breakpoint) { - return true; - } - - public BreakpointItem createBreakpointItem(final Breakpoint breakpoint) { - return new JavaBreakpointItem(this, breakpoint); - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java index 1bcbf3e9954b..76c55c7b4ae9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java @@ -20,14 +20,11 @@ */ package com.intellij.debugger.ui.breakpoints; -import com.intellij.codeInsight.folding.impl.actions.ExpandRegionAction; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerInvocationUtil; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.BreakpointStepMethodFilter; import com.intellij.debugger.engine.DebugProcessImpl; -import com.intellij.debugger.engine.evaluation.CodeFragmentKind; -import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerContextListener; @@ -35,41 +32,31 @@ import com.intellij.debugger.impl.DebuggerManagerImpl; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.ui.JavaDebuggerSupport; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorFactory; -import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.openapi.editor.markup.MarkupEditorFilterFactory; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileEditor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.TextEditor; -import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiField; import com.intellij.psi.PsiFile; import com.intellij.util.Alarm; import com.intellij.util.EventDispatcher; -import com.intellij.util.IJSwingUtilities; -import com.intellij.util.SystemProperties; -import com.intellij.util.containers.MultiMap; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.XDebuggerUtil; -import com.intellij.xdebugger.breakpoints.XBreakpointType; +import com.intellij.xdebugger.breakpoints.*; import com.intellij.xdebugger.impl.DebuggerSupport; import com.intellij.xdebugger.impl.XDebugSessionImpl; -import com.sun.jdi.Field; +import com.intellij.xdebugger.impl.breakpoints.XBreakpointManagerImpl; +import com.intellij.xdebugger.impl.breakpoints.XDependentBreakpointManager; import com.sun.jdi.InternalException; -import com.sun.jdi.ObjectReference; import com.sun.jdi.ThreadReference; import com.sun.jdi.request.*; import gnu.trove.THashMap; @@ -78,11 +65,9 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.java.debugger.breakpoints.JavaBreakpointAdapter; -import org.jetbrains.java.debugger.breakpoints.JavaBreakpointType; +import org.jetbrains.java.debugger.breakpoints.properties.JavaExceptionBreakpointProperties; import javax.swing.*; -import java.awt.event.MouseEvent; import java.util.*; public class BreakpointManager { @@ -94,15 +79,13 @@ public class BreakpointManager { @NonNls private static final String DEFAULT_CONDITION_STATE_ATTRIBUTE_NAME = "default_condition_enabled"; @NonNls private static final String RULES_GROUP_NAME = "breakpoint_rules"; + private static final String CONVERTED_PARAM = "converted"; private final Project myProject; - private AnyExceptionBreakpoint myAnyExceptionBreakpoint; - private final List<Breakpoint> myBreakpoints = new ArrayList<Breakpoint>(); // breakpoints storage, access should be synchronized - private final List<EnableBreakpointRule> myBreakpointRules = new ArrayList<EnableBreakpointRule>(); // breakpoint rules + private final Map<XBreakpoint, Breakpoint> myBreakpoints = new HashMap<XBreakpoint, Breakpoint>(); // breakpoints storage, access should be synchronized @Nullable private List<Breakpoint> myBreakpointsListForIteration = null; // another list for breakpoints iteration, unsynchronized access ok - private final MultiMap<Document, BreakpointWithHighlighter> myDocumentBreakpoints = MultiMap.createSmartList(); private final Map<String, String> myUIProperties = new LinkedHashMap<String, String>(); - private final Map<Key<? extends Breakpoint>, BreakpointDefaults> myBreakpointDefaults = new LinkedHashMap<Key<? extends Breakpoint>, BreakpointDefaults>(); + //private final Map<Key<? extends Breakpoint>, BreakpointDefaults> myBreakpointDefaults = new LinkedHashMap<Key<? extends Breakpoint>, BreakpointDefaults>(); private final EventDispatcher<BreakpointManagerListener> myDispatcher = EventDispatcher.create(BreakpointManagerListener.class); @@ -155,212 +138,35 @@ public class BreakpointManager { } } }); - - if (!project.isDefault()) { - XDebuggerManager.getInstance(project).getBreakpointManager().addBreakpointListener( - XBreakpointType.EXTENSION_POINT_NAME.findExtension(JavaBreakpointType.class), new JavaBreakpointAdapter(project), project); - } } public void init() { - EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster(); - eventMulticaster.addEditorMouseListener(new EditorMouseAdapter() { - @Nullable private EditorMouseEvent myMousePressedEvent; - - @Nullable - private Breakpoint toggleBreakpoint(final boolean mostSuitingBreakpoint, final int line, boolean temporary) { - final Editor editor = FileEditorManager.getInstance(myProject).getSelectedTextEditor(); - if (editor == null) { - return null; - } - final Document document = editor.getDocument(); - final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document); - if (!JavaBreakpointType.doCanPutAt(psiFile)) { - return null; - } - - if (SystemProperties.getBooleanProperty("java.debugger.xBreakpoint", false) && - XBreakpointType.EXTENSION_POINT_NAME.findExtension(JavaBreakpointType.class) - .canPutAt(psiFile.getVirtualFile(), line, myProject)) { - return null; - } - - PsiDocumentManager.getInstance(myProject).commitDocument(document); - - int offset = editor.getCaretModel().getOffset(); - int editorLine = editor.getDocument().getLineNumber(offset); - if (editorLine != line) { - if (line < 0 || line >= document.getLineCount()) { - return null; - } - offset = editor.getDocument().getLineStartOffset(line); - } - - ExpandRegionAction.expandRegionAtOffset(myProject, editor, offset); - - Breakpoint breakpoint = findBreakpoint(document, offset, null); - if (breakpoint == null) { - boolean isInsideCompiledClass = StdFileTypes.CLASS.equals(psiFile.getFileType()); - if (mostSuitingBreakpoint || isInsideCompiledClass) { - breakpoint = addFieldBreakpoint(document, offset); - if (breakpoint == null) { - breakpoint = addMethodBreakpoint(document, line); - } - if (breakpoint == null && !isInsideCompiledClass) { - breakpoint = addLineBreakpoint(document, line); - } - } - else { - breakpoint = addLineBreakpoint(document, line); - - if (breakpoint == null) { - breakpoint = addMethodBreakpoint(document, line); - } - } - - if (breakpoint != null) { - breakpoint.REMOVE_AFTER_HIT = temporary; - RequestManagerImpl.createRequests(breakpoint); - } - return breakpoint; - } - else { - removeBreakpoint(breakpoint); - return null; - } - } - - private boolean isFromMyProject(Editor editor) { - FileEditor[] allEditors = FileEditorManager.getInstance(myProject).getAllEditors(); - for (FileEditor ed : allEditors) { - if (!(ed instanceof TextEditor)) { - continue; - } - if (((TextEditor)ed).getEditor().equals(editor)) { - return true; - } - } - return false; - } - - //mousePressed + mouseReleased is a hack to keep selection in editor when shift is pressed + XBreakpointManager manager = XDebuggerManager.getInstance(myProject).getBreakpointManager(); + manager.addBreakpointListener(new XBreakpointListener() { @Override - public void mousePressed(@NotNull EditorMouseEvent e) { - if (MarkupEditorFilterFactory.createIsDiffFilter().avaliableIn(e.getEditor())) return; - - if (e.isConsumed()) return; - - if (e.getArea() == EditorMouseEventArea.LINE_MARKERS_AREA && e.getMouseEvent().isShiftDown()) { - myMousePressedEvent = e; - e.consume(); + public void breakpointAdded(@NotNull XBreakpoint xBreakpoint) { + if (isJavaType(xBreakpoint)) { + onBreakpointAdded(xBreakpoint); } } @Override - public void mouseReleased(@NotNull EditorMouseEvent e) { - if (myMousePressedEvent != null) { - mouseClicked(e); - } - myMousePressedEvent = null; + public void breakpointRemoved(@NotNull XBreakpoint xBreakpoint) { + onBreakpointRemoved(xBreakpoint); } @Override - public void mouseClicked(@NotNull final EditorMouseEvent e) { - if (MarkupEditorFilterFactory.createIsDiffFilter().avaliableIn(e.getEditor())) return; - - if (e.isConsumed()) return; - - if (e.getArea() == EditorMouseEventArea.LINE_MARKERS_AREA) { - PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(new Runnable() { - @Override - public void run() { - final Editor editor = e.getEditor(); - if (!isFromMyProject(editor)) { - return; - } - final int line = editor.xyToLogicalPosition(e.getMouseEvent().getPoint()).line; - final Document document = editor.getDocument(); - if (line < 0 || line >= document.getLineCount()) { - return; - } - MouseEvent event = e.getMouseEvent(); - if (event.isPopupTrigger()) { - return; - } - if (event.getButton() != 1) { - return; - } - if (e.getMouseEvent().isControlDown() || e.getMouseEvent().isMetaDown()) { - return; - } - - VirtualFile file = FileDocumentManager.getInstance().getFile(document); - if (file != null && XDebuggerUtil.getInstance().canPutBreakpointAt(myProject, file, line)) { - return; - } - e.consume(); - - DebuggerInvocationUtil.invokeLater(myProject, new Runnable() { - @Override - public void run() { - final boolean suitingBreakpoint = e.getMouseEvent().isAltDown() && !e.getMouseEvent().isShiftDown(); - final boolean temporary = e.getMouseEvent().isAltDown() && e.getMouseEvent().isShiftDown(); - - final Breakpoint breakpoint = toggleBreakpoint(suitingBreakpoint, line, temporary); - - - if (!e.getMouseEvent().isAltDown() && e.getMouseEvent().isShiftDown() && breakpoint != null) { - breakpoint.LOG_EXPRESSION_ENABLED = true; - String selection = editor.getSelectionModel().getSelectedText(); - String text = selection != null ? selection : DebuggerBundle.message("breakpoint.log.message", - breakpoint.getDisplayName()); - breakpoint.setLogMessage(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, text)); - breakpoint.SUSPEND = false; - editBreakpoint(breakpoint, editor); - - - //DialogWrapper dialog = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager() - // .createConfigurationDialog(breakpoint, BreakpointPropertiesPanel.CONTROL_LOG_MESSAGE); - //dialog.show(); - // - //if (!dialog.isOK()) { - // removeBreakpoint(breakpoint); - //} - } - } - }); - } - }); + public void breakpointChanged(@NotNull XBreakpoint xBreakpoint) { + Breakpoint breakpoint = myBreakpoints.get(xBreakpoint); + if (breakpoint != null) { + fireBreakpointChanged(breakpoint); } } - }, myProject); - - eventMulticaster.addDocumentListener(new DocumentAdapter() { - private final Alarm myUpdateAlarm = new Alarm(); + }); + } - @Override - public void documentChanged(@NotNull final DocumentEvent e) { - final Document document = e.getDocument(); - //noinspection SynchronizeOnThis - synchronized (BreakpointManager.this) { - Collection<BreakpointWithHighlighter> breakpoints = myDocumentBreakpoints.get(document); - if (!breakpoints.isEmpty()) { - myUpdateAlarm.cancelAllRequests(); - // must create new array in order to avoid "concurrent modification" errors - final List<BreakpointWithHighlighter> breakpointsToUpdate = new ArrayList<BreakpointWithHighlighter>(breakpoints); - myUpdateAlarm.addRequest(new Runnable() { - @Override - public void run() { - if (!myProject.isDisposed()) { - PsiDocumentManager.getInstance(myProject).commitDocument(document); - update(breakpointsToUpdate); - } - } - }, 300, ModalityState.NON_MODAL); - } - } - } - }, myProject); + private XBreakpointManager getXBreakpointManager() { + return XDebuggerManager.getInstance(myProject).getBreakpointManager(); } public void editBreakpoint(final Breakpoint breakpoint, final Editor editor) { @@ -380,17 +186,34 @@ public class BreakpointManager { }); } - @NotNull - public BreakpointDefaults getBreakpointDefaults(Key<? extends Breakpoint> category) { - BreakpointDefaults defaults = myBreakpointDefaults.get(category); - if (defaults == null) { - defaults = new BreakpointDefaults(); - } - return defaults; - } + //@NotNull + //public BreakpointDefaults getBreakpointDefaults(Key<? extends Breakpoint> category) { + // BreakpointDefaults defaults = myBreakpointDefaults.get(category); + // if (defaults == null) { + // defaults = new BreakpointDefaults(); + // } + // return defaults; + //} public void setBreakpointDefaults(Key<? extends Breakpoint> category, BreakpointDefaults defaults) { - myBreakpointDefaults.put(category, defaults); + Class typeCls = null; + if (LineBreakpoint.CATEGORY.toString().equals(category.toString())) { + typeCls = JavaLineBreakpointType.class; + } + else if (MethodBreakpoint.CATEGORY.toString().equals(category.toString())) { + typeCls = JavaMethodBreakpointType.class; + } + else if (FieldBreakpoint.CATEGORY.toString().equals(category.toString())) { + typeCls = JavaFieldBreakpointType.class; + } + else if (ExceptionBreakpoint.CATEGORY.toString().equals(category.toString())) { + typeCls = JavaExceptionBreakpointType.class; + } + if (typeCls != null) { + XBreakpointType<XBreakpoint<?>, ?> type = XDebuggerUtil.getInstance().findBreakpointType(typeCls); + ((XBreakpointManagerImpl)getXBreakpointManager()).getBreakpointDefaults(type).setSuspendPolicy(Breakpoint.transformSuspendPolicy(defaults.getSuspendPolicy())); + } + //myBreakpointDefaults.put(category, defaults); } @@ -410,8 +233,8 @@ public class BreakpointManager { if (!LineBreakpoint.canAddLineBreakpoint(myProject, document, lineIndex)) { return null; } - - LineBreakpoint breakpoint = LineBreakpoint.create(myProject, document, lineIndex); + XLineBreakpoint xLineBreakpoint = addXLineBreakpoint(JavaLineBreakpointType.class, document, lineIndex); + LineBreakpoint breakpoint = LineBreakpoint.create(myProject, xLineBreakpoint); if (breakpoint == null) { return null; } @@ -420,15 +243,15 @@ public class BreakpointManager { return breakpoint; } - @Nullable - public FieldBreakpoint addFieldBreakpoint(Field field, ObjectReference object) { - ApplicationManager.getApplication().assertIsDispatchThread(); - final FieldBreakpoint fieldBreakpoint = FieldBreakpoint.create(myProject, field, object); - if (fieldBreakpoint != null) { - addBreakpoint(fieldBreakpoint); - } - return fieldBreakpoint; - } + //@Nullable + //public FieldBreakpoint addFieldBreakpoint(Field field, ObjectReference object) { + // ApplicationManager.getApplication().assertIsDispatchThread(); + // final FieldBreakpoint fieldBreakpoint = FieldBreakpoint.create(myProject, field, object, null); + // if (fieldBreakpoint != null) { + // addBreakpoint(fieldBreakpoint); + // } + // return fieldBreakpoint; + //} @Nullable public FieldBreakpoint addFieldBreakpoint(@NotNull Document document, int offset) { @@ -449,7 +272,8 @@ public class BreakpointManager { @Nullable public FieldBreakpoint addFieldBreakpoint(Document document, int lineIndex, String fieldName) { ApplicationManager.getApplication().assertIsDispatchThread(); - FieldBreakpoint fieldBreakpoint = FieldBreakpoint.create(myProject, document, lineIndex, fieldName); + XLineBreakpoint xBreakpoint = addXLineBreakpoint(JavaFieldBreakpointType.class, document, lineIndex); + FieldBreakpoint fieldBreakpoint = FieldBreakpoint.create(myProject, fieldName, xBreakpoint); if (fieldBreakpoint != null) { addBreakpoint(fieldBreakpoint); } @@ -457,21 +281,30 @@ public class BreakpointManager { } @NotNull - public ExceptionBreakpoint addExceptionBreakpoint(@NotNull String exceptionClassName, String packageName) { + public ExceptionBreakpoint addExceptionBreakpoint(@NotNull final String exceptionClassName, final String packageName) { ApplicationManager.getApplication().assertIsDispatchThread(); - ExceptionBreakpoint breakpoint = new ExceptionBreakpoint(myProject, exceptionClassName, packageName); - addBreakpoint(breakpoint); - if (LOG.isDebugEnabled()) { - LOG.debug("ExceptionBreakpoint Added"); - } - return breakpoint; + final JavaExceptionBreakpointType type = (JavaExceptionBreakpointType)XDebuggerUtil.getInstance().findBreakpointType(JavaExceptionBreakpointType.class); + return ApplicationManager.getApplication().runWriteAction(new Computable<ExceptionBreakpoint>() { + @Override + public ExceptionBreakpoint compute() { + XBreakpoint<JavaExceptionBreakpointProperties> xBreakpoint = XDebuggerManager.getInstance(myProject).getBreakpointManager() + .addBreakpoint(type, new JavaExceptionBreakpointProperties(exceptionClassName, packageName)); + ExceptionBreakpoint breakpoint = new ExceptionBreakpoint(myProject, exceptionClassName, packageName, xBreakpoint); + addBreakpoint(breakpoint); + if (LOG.isDebugEnabled()) { + LOG.debug("ExceptionBreakpoint Added"); + } + return breakpoint; + } + }); } @Nullable public MethodBreakpoint addMethodBreakpoint(Document document, int lineIndex) { ApplicationManager.getApplication().assertIsDispatchThread(); - MethodBreakpoint breakpoint = MethodBreakpoint.create(myProject, document, lineIndex); + XLineBreakpoint xBreakpoint = addXLineBreakpoint(JavaMethodBreakpointType.class, document, lineIndex); + MethodBreakpoint breakpoint = MethodBreakpoint.create(myProject, xBreakpoint); if (breakpoint == null) { return null; } @@ -482,10 +315,23 @@ public class BreakpointManager { return breakpoint; } + private <B extends XBreakpoint<?>> XLineBreakpoint addXLineBreakpoint(Class<? extends XBreakpointType<B,?>> typeCls, Document document, final int lineIndex) { + final XBreakpointType<B, ?> type = XDebuggerUtil.getInstance().findBreakpointType(typeCls); + final VirtualFile file = FileDocumentManager.getInstance().getFile(document); + return ApplicationManager.getApplication().runWriteAction(new Computable<XLineBreakpoint>() { + @Override + public XLineBreakpoint compute() { + return XDebuggerManager.getInstance(myProject).getBreakpointManager() + .addLineBreakpoint((XLineBreakpointType)type, file.getUrl(), lineIndex, + ((XLineBreakpointType)type).createBreakpointProperties(file, lineIndex)); + } + }); + } + @Nullable public WildcardMethodBreakpoint addMethodBreakpoint(String classPattern, String methodName) { ApplicationManager.getApplication().assertIsDispatchThread(); - WildcardMethodBreakpoint breakpoint = WildcardMethodBreakpoint.create(myProject, classPattern, methodName); + WildcardMethodBreakpoint breakpoint = WildcardMethodBreakpoint.create(myProject, classPattern, methodName, null); if (breakpoint == null) { return null; } @@ -531,14 +377,6 @@ public class BreakpointManager { */ @Nullable public <T extends BreakpointWithHighlighter> T findBreakpoint(final Document document, final int offset, @Nullable final Key<T> category) { - for (BreakpointWithHighlighter breakpointWithHighlighter : myDocumentBreakpoints.get(document)) { - if (breakpointWithHighlighter.isAt(document, offset) && - (category == null || category.equals(breakpointWithHighlighter.getCategory()))) { - //noinspection unchecked - return (T)breakpointWithHighlighter; - } - } - for (final Breakpoint breakpoint : getBreakpoints()) { if (breakpoint instanceof BreakpointWithHighlighter && ((BreakpointWithHighlighter)breakpoint).isAt(document, offset)) { if (category == null || category.equals(breakpoint.getCategory())) { @@ -550,7 +388,17 @@ public class BreakpointManager { return null; } + public Breakpoint findBreakpoint(XBreakpoint xBreakpoint) { + return myBreakpoints.get(xBreakpoint); + } + + private List<Element> myOriginalBreakpointsNodes = new ArrayList<Element>(); + public void readExternal(@NotNull final Element parentNode) { + // save old breakpoints + for (Element element : parentNode.getChildren()) { + myOriginalBreakpointsNodes.add(element.clone()); + } if (myProject.isOpen()) { doRead(parentNode); } @@ -577,6 +425,10 @@ public class BreakpointManager { if (group.getName().equals(RULES_GROUP_NAME)) { continue; } + // skip already converted + if (group.getAttribute(CONVERTED_PARAM) != null) { + continue; + } final String categoryName = group.getName(); final Key<Breakpoint> breakpointCategory = BreakpointCategory.lookup(categoryName); final String defaultPolicy = group.getAttributeValue(DEFAULT_SUSPEND_POLICY_ATTRIBUTE_NAME); @@ -586,16 +438,15 @@ public class BreakpointManager { if (!AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT.equals(breakpointCategory)) { // for compatibility with previous format anyExceptionBreakpointGroup = group.getChild(AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT.toString()); - final BreakpointFactory factory = BreakpointFactory.getInstance(breakpointCategory); - if (factory != null) { - for (final Object o : group.getChildren("breakpoint")) { - Element breakpointNode = (Element)o; - Breakpoint breakpoint = factory.createBreakpoint(myProject, breakpointNode); + //final BreakpointFactory factory = BreakpointFactory.getInstance(breakpointCategory); + //if (factory != null) { + for (Element breakpointNode : group.getChildren("breakpoint")) { + //Breakpoint breakpoint = factory.createBreakpoint(myProject, breakpointNode); + Breakpoint breakpoint = createBreakpoint(categoryName, breakpointNode); breakpoint.readExternal(breakpointNode); - addBreakpoint(breakpoint); nameToBreakpointMap.put(breakpoint.getDisplayName(), breakpoint); } - } + //} } else { anyExceptionBreakpointGroup = group; @@ -604,10 +455,14 @@ public class BreakpointManager { if (anyExceptionBreakpointGroup != null) { final Element breakpointElement = group.getChild("breakpoint"); if (breakpointElement != null) { - getAnyExceptionBreakpoint().readExternal(breakpointElement); + XBreakpointManager manager = XDebuggerManager.getInstance(myProject).getBreakpointManager(); + JavaExceptionBreakpointType type = (JavaExceptionBreakpointType)XDebuggerUtil.getInstance().findBreakpointType(JavaExceptionBreakpointType.class); + XBreakpoint<JavaExceptionBreakpointProperties> xBreakpoint = manager.getDefaultBreakpoint(type); + Breakpoint breakpoint = createJavaBreakpoint(xBreakpoint); + breakpoint.readExternal(breakpointElement); + addBreakpoint(breakpoint); } } - } } catch (InvalidDataException ignored) { @@ -615,9 +470,12 @@ public class BreakpointManager { final Element rulesGroup = parentNode.getChild(RULES_GROUP_NAME); if (rulesGroup != null) { - final List rules = rulesGroup.getChildren("rule"); - for (final Object rule1 : rules) { - final Element rule = (Element)rule1; + final List<Element> rules = rulesGroup.getChildren("rule"); + for (Element rule : rules) { + // skip already converted + if (rule.getAttribute(CONVERTED_PARAM) != null) { + continue; + } final Element master = rule.getChild(MASTER_BREAKPOINT_TAGNAME); if (master == null) { continue; @@ -634,7 +492,11 @@ public class BreakpointManager { if (slaveBreakpoint == null) { continue; } - addBreakpointRule(new EnableBreakpointRule(BreakpointManager.this, masterBreakpoint, slaveBreakpoint, "true".equalsIgnoreCase(rule.getAttributeValue("leaveEnabled")))); + + boolean leaveEnabled = "true".equalsIgnoreCase(rule.getAttributeValue("leaveEnabled")); + XDependentBreakpointManager dependentBreakpointManager = ((XBreakpointManagerImpl)getXBreakpointManager()).getDependentBreakpointManager(); + dependentBreakpointManager.setMasterBreakpoint(slaveBreakpoint.myXBreakpoint, masterBreakpoint.myXBreakpoint, leaveEnabled); + //addBreakpointRule(new EnableBreakpointRule(BreakpointManager.this, masterBreakpoint, slaveBreakpoint, leaveEnabled)); } } @@ -662,112 +524,190 @@ public class BreakpointManager { } } + private Breakpoint createBreakpoint(String category, Element breakpointNode) throws InvalidDataException { + XBreakpoint xBreakpoint = null; + if (category.equals(LineBreakpoint.CATEGORY.toString())) { + xBreakpoint = createXLineBreakpoint(JavaLineBreakpointType.class, breakpointNode); + } + else if (category.equals(MethodBreakpoint.CATEGORY.toString())) { + if (breakpointNode.getAttribute("url") != null) { + xBreakpoint = createXLineBreakpoint(JavaMethodBreakpointType.class, breakpointNode); + } + else { + xBreakpoint = createXBreakpoint(JavaWildcardMethodBreakpointType.class, breakpointNode); + } + } + else if (category.equals(FieldBreakpoint.CATEGORY.toString())) { + xBreakpoint = createXLineBreakpoint(JavaFieldBreakpointType.class, breakpointNode); + } + else if (category.equals(ExceptionBreakpoint.CATEGORY.toString())) { + xBreakpoint = createXBreakpoint(JavaExceptionBreakpointType.class, breakpointNode); + } + if (xBreakpoint == null) { + throw new IllegalStateException("Unknown breakpoint category " + category); + } + return myBreakpoints.get(xBreakpoint); + } + + private <B extends XBreakpoint<?>> XBreakpoint createXBreakpoint(Class<? extends XBreakpointType<B, ?>> typeCls, + Element breakpointNode) throws InvalidDataException { + final XBreakpointType<B, ?> type = XDebuggerUtil.getInstance().findBreakpointType(typeCls); + return ApplicationManager.getApplication().runWriteAction(new Computable<XBreakpoint>() { + @Override + public XBreakpoint compute() { + return XDebuggerManager.getInstance(myProject).getBreakpointManager() + .addBreakpoint((XBreakpointType)type, type.createProperties()); + }}); + } + + private <B extends XBreakpoint<?>> XLineBreakpoint createXLineBreakpoint(Class<? extends XBreakpointType<B, ?>> typeCls, + Element breakpointNode) throws InvalidDataException { + final String url = breakpointNode.getAttributeValue("url"); + VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url); + if (vFile == null) { + throw new InvalidDataException(DebuggerBundle.message("error.breakpoint.file.not.found", url)); + } + final Document doc = FileDocumentManager.getInstance().getDocument(vFile); + if (doc == null) { + throw new InvalidDataException(DebuggerBundle.message("error.cannot.load.breakpoint.file", url)); + } + + final int line; + try { + //noinspection HardCodedStringLiteral + line = Integer.parseInt(breakpointNode.getAttributeValue("line")); + } + catch (Exception e) { + throw new InvalidDataException("Line number is invalid for breakpoint"); + } + return addXLineBreakpoint(typeCls, doc, line); + } + //used in Fabrique public synchronized void addBreakpoint(Breakpoint breakpoint) { - myBreakpoints.add(breakpoint); + myBreakpoints.put(breakpoint.myXBreakpoint, breakpoint); myBreakpointsListForIteration = null; - if (breakpoint instanceof BreakpointWithHighlighter) { - BreakpointWithHighlighter breakpointWithHighlighter = (BreakpointWithHighlighter)breakpoint; - final Document document = breakpointWithHighlighter.getDocument(); - if (document != null) { - myDocumentBreakpoints.putValue(document, breakpointWithHighlighter); - } - } + breakpoint.updateUI(); + RequestManagerImpl.createRequests(breakpoint); myDispatcher.getMulticaster().breakpointsChanged(); + if (breakpoint instanceof MethodBreakpoint || breakpoint instanceof WildcardMethodBreakpoint) { + XDebugSessionImpl.NOTIFICATION_GROUP.createNotification("Method breakpoints may dramatically slow down debugging", MessageType.WARNING).notify(myProject); + } } - public synchronized void removeBreakpoint(@Nullable final Breakpoint breakpoint) { - ApplicationManager.getApplication().assertIsDispatchThread(); + private synchronized void onBreakpointAdded(XBreakpoint xBreakpoint) { + Breakpoint breakpoint = createJavaBreakpoint(xBreakpoint); + addBreakpoint(breakpoint); + } + + public void removeBreakpoint(@Nullable final Breakpoint breakpoint) { if (breakpoint == null) { return; } + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + getXBreakpointManager().removeBreakpoint(breakpoint.myXBreakpoint); + } + }); + } + + private synchronized void onBreakpointRemoved(@Nullable final XBreakpoint xBreakpoint) { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (xBreakpoint == null) { + return; + } - if (myBreakpoints.remove(breakpoint)) { - updateBreakpointRules(breakpoint); + Breakpoint breakpoint = myBreakpoints.remove(xBreakpoint); + if (breakpoint != null) { + //updateBreakpointRules(breakpoint); myBreakpointsListForIteration = null; - if (breakpoint instanceof BreakpointWithHighlighter) { - for (Document document : myDocumentBreakpoints.keySet()) { - if (myDocumentBreakpoints.remove(document, (BreakpointWithHighlighter)breakpoint)) { - break; - } - } - } //we delete breakpoints inside release, so gutter will not fire events to deleted breakpoints breakpoint.delete(); + RequestManagerImpl.deleteRequests(breakpoint); myDispatcher.getMulticaster().breakpointsChanged(); } } public void writeExternal(@NotNull final Element parentNode) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - removeInvalidBreakpoints(); - final Map<Key<? extends Breakpoint>, Element> categoryToElementMap = new THashMap<Key<? extends Breakpoint>, Element>(); - for (Key<? extends Breakpoint> category : myBreakpointDefaults.keySet()) { - final Element group = getCategoryGroupElement(categoryToElementMap, category, parentNode); - final BreakpointDefaults defaults = getBreakpointDefaults(category); - group.setAttribute(DEFAULT_SUSPEND_POLICY_ATTRIBUTE_NAME, String.valueOf(defaults.getSuspendPolicy())); - group.setAttribute(DEFAULT_CONDITION_STATE_ATTRIBUTE_NAME, String.valueOf(defaults.isConditionEnabled())); - } - // don't store invisible breakpoints - for (Breakpoint breakpoint : getBreakpoints()) { - if (breakpoint.isValid() && - (!(breakpoint instanceof BreakpointWithHighlighter) || ((BreakpointWithHighlighter)breakpoint).isVisible())) { - writeBreakpoint(getCategoryGroupElement(categoryToElementMap, breakpoint.getCategory(), parentNode), breakpoint); - } - } - final AnyExceptionBreakpoint anyExceptionBreakpoint = getAnyExceptionBreakpoint(); - final Element group = getCategoryGroupElement(categoryToElementMap, anyExceptionBreakpoint.getCategory(), parentNode); - writeBreakpoint(group, anyExceptionBreakpoint); - - final Element rules = new Element(RULES_GROUP_NAME); - parentNode.addContent(rules); - for (EnableBreakpointRule myBreakpointRule : myBreakpointRules) { - writeRule(myBreakpointRule, rules); - } + // restore old breakpoints + for (Element group : myOriginalBreakpointsNodes) { + if (group.getAttribute(CONVERTED_PARAM) == null) { + group.setAttribute(CONVERTED_PARAM, "true"); } - }); - - final Element uiProperties = new Element("ui_properties"); - parentNode.addContent(uiProperties); - for (final String name : myUIProperties.keySet()) { - Element property = new Element("property"); - uiProperties.addContent(property); - property.setAttribute("name", name); - property.setAttribute("value", myUIProperties.get(name)); - } - } - - @SuppressWarnings({"HardCodedStringLiteral"}) - private static void writeRule(@NotNull final EnableBreakpointRule enableBreakpointRule, @NotNull Element element) { - Element rule = new Element("rule"); - if (enableBreakpointRule.isLeaveEnabled()) { - rule.setAttribute("leaveEnabled", Boolean.toString(true)); + group.detach(); } - element.addContent(rule); - writeRuleBreakpoint(rule, MASTER_BREAKPOINT_TAGNAME, enableBreakpointRule.getMasterBreakpoint()); - writeRuleBreakpoint(rule, SLAVE_BREAKPOINT_TAGNAME, enableBreakpointRule.getSlaveBreakpoint()); - } - @SuppressWarnings({"HardCodedStringLiteral"}) private static void writeRuleBreakpoint(@NotNull final Element element, final String tagName, @NotNull final Breakpoint breakpoint) { - Element master = new Element(tagName); - element.addContent(master); - master.setAttribute("name", breakpoint.getDisplayName()); + parentNode.addContent(myOriginalBreakpointsNodes); + //ApplicationManager.getApplication().runReadAction(new Runnable() { + // @Override + // public void run() { + // removeInvalidBreakpoints(); + // final Map<Key<? extends Breakpoint>, Element> categoryToElementMap = new THashMap<Key<? extends Breakpoint>, Element>(); + // for (Key<? extends Breakpoint> category : myBreakpointDefaults.keySet()) { + // final Element group = getCategoryGroupElement(categoryToElementMap, category, parentNode); + // final BreakpointDefaults defaults = getBreakpointDefaults(category); + // group.setAttribute(DEFAULT_SUSPEND_POLICY_ATTRIBUTE_NAME, String.valueOf(defaults.getSuspendPolicy())); + // group.setAttribute(DEFAULT_CONDITION_STATE_ATTRIBUTE_NAME, String.valueOf(defaults.isConditionEnabled())); + // } + // // don't store invisible breakpoints + // for (Breakpoint breakpoint : getBreakpoints()) { + // if (breakpoint.isValid() && + // (!(breakpoint instanceof BreakpointWithHighlighter) || ((BreakpointWithHighlighter)breakpoint).isVisible())) { + // writeBreakpoint(getCategoryGroupElement(categoryToElementMap, breakpoint.getCategory(), parentNode), breakpoint); + // } + // } + // final AnyExceptionBreakpoint anyExceptionBreakpoint = getAnyExceptionBreakpoint(); + // final Element group = getCategoryGroupElement(categoryToElementMap, anyExceptionBreakpoint.getCategory(), parentNode); + // writeBreakpoint(group, anyExceptionBreakpoint); + // + // final Element rules = new Element(RULES_GROUP_NAME); + // parentNode.addContent(rules); + // //for (EnableBreakpointRule myBreakpointRule : myBreakpointRules) { + // // writeRule(myBreakpointRule, rules); + // //} + // } + //}); + // + //final Element uiProperties = new Element("ui_properties"); + //parentNode.addContent(uiProperties); + //for (final String name : myUIProperties.keySet()) { + // Element property = new Element("property"); + // uiProperties.addContent(property); + // property.setAttribute("name", name); + // property.setAttribute("value", myUIProperties.get(name)); + //} } - @SuppressWarnings({"HardCodedStringLiteral"}) - private static void writeBreakpoint(@NotNull final Element group, @NotNull final Breakpoint breakpoint) { - Element breakpointNode = new Element("breakpoint"); - group.addContent(breakpointNode); - try { - breakpoint.writeExternal(breakpointNode); - } - catch (WriteExternalException e) { - LOG.error(e); - } - } + //@SuppressWarnings({"HardCodedStringLiteral"}) + //private static void writeRule(@NotNull final EnableBreakpointRule enableBreakpointRule, @NotNull Element element) { + // Element rule = new Element("rule"); + // if (enableBreakpointRule.isLeaveEnabled()) { + // rule.setAttribute("leaveEnabled", Boolean.toString(true)); + // } + // element.addContent(rule); + // writeRuleBreakpoint(rule, MASTER_BREAKPOINT_TAGNAME, enableBreakpointRule.getMasterBreakpoint()); + // writeRuleBreakpoint(rule, SLAVE_BREAKPOINT_TAGNAME, enableBreakpointRule.getSlaveBreakpoint()); + //} + + //@SuppressWarnings({"HardCodedStringLiteral"}) private static void writeRuleBreakpoint(@NotNull final Element element, final String tagName, @NotNull final Breakpoint breakpoint) { + // Element master = new Element(tagName); + // element.addContent(master); + // master.setAttribute("name", breakpoint.getDisplayName()); + //} + + //@SuppressWarnings({"HardCodedStringLiteral"}) + //private static void writeBreakpoint(@NotNull final Element group, @NotNull final Breakpoint breakpoint) { + // Element breakpointNode = new Element("breakpoint"); + // group.addContent(breakpointNode); + // try { + // breakpoint.writeExternal(breakpointNode); + // } + // catch (WriteExternalException e) { + // LOG.error(e); + // } + //} private static <T extends Breakpoint> Element getCategoryGroupElement(@NotNull final Map<Key<? extends Breakpoint>, Element> categoryToElementMap, @NotNull final Key<T> category, @NotNull final Element parentNode) { Element group = categoryToElementMap.get(category); @@ -814,18 +754,37 @@ public class BreakpointManager { @NotNull public synchronized List<Breakpoint> getBreakpoints() { if (myBreakpointsListForIteration == null) { - myBreakpointsListForIteration = new ArrayList<Breakpoint>(myBreakpoints.size() + 1); - myBreakpointsListForIteration.addAll(myBreakpoints); - myBreakpointsListForIteration.add(getAnyExceptionBreakpoint()); + myBreakpointsListForIteration = new ArrayList<Breakpoint>(myBreakpoints.size()); + + XBreakpoint<?>[] xBreakpoints = ApplicationManager.getApplication().runReadAction(new Computable<XBreakpoint<?>[]>() { + public XBreakpoint<?>[] compute() { + return getXBreakpointManager().getAllBreakpoints(); + } + }); + for (XBreakpoint<?> xBreakpoint : xBreakpoints) { + if (isJavaType(xBreakpoint)) { + Breakpoint breakpoint = myBreakpoints.get(xBreakpoint); + if (breakpoint == null) { + breakpoint = createJavaBreakpoint(xBreakpoint); + myBreakpoints.put(xBreakpoint, breakpoint); + } + } + } + + myBreakpointsListForIteration.addAll(myBreakpoints.values()); } return myBreakpointsListForIteration; } - public AnyExceptionBreakpoint getAnyExceptionBreakpoint() { - if (myAnyExceptionBreakpoint == null) { - myAnyExceptionBreakpoint = new AnyExceptionBreakpoint(myProject); + private boolean isJavaType(XBreakpoint xBreakpoint) { + return xBreakpoint.getType() instanceof JavaBreakpointType; + } + + private Breakpoint createJavaBreakpoint(XBreakpoint xBreakpoint) { + if (xBreakpoint.getType() instanceof JavaBreakpointType) { + return ((JavaBreakpointType)xBreakpoint.getType()).createJavaBreakpoint(myProject, xBreakpoint); } - return myAnyExceptionBreakpoint; + throw new IllegalStateException("Unsupported breakpoint type:" + xBreakpoint.getType()); } //interaction with RequestManagerImpl @@ -963,6 +922,8 @@ public class BreakpointManager { private boolean myAllowMulticasting = true; private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); public void fireBreakpointChanged(Breakpoint breakpoint) { + breakpoint.reload(); + breakpoint.updateUI(); RequestManagerImpl.updateRequests(breakpoint); if (myAllowMulticasting) { // can be invoked from non-AWT thread @@ -988,84 +949,103 @@ public class BreakpointManager { } public void setBreakpointEnabled(@NotNull final Breakpoint breakpoint, final boolean enabled) { - if (breakpoint.ENABLED != enabled) { - breakpoint.ENABLED = enabled; - fireBreakpointChanged(breakpoint); - breakpoint.updateUI(); + if (breakpoint.isEnabled() != enabled) { + breakpoint.setEnabled(enabled); + //fireBreakpointChanged(breakpoint); + //breakpoint.updateUI(); } } public void addBreakpointRule(@NotNull EnableBreakpointRule rule) { - rule.init(); - myBreakpointRules.add(rule); + //rule.init(); + //myBreakpointRules.add(rule); } public boolean removeBreakpointRule(@NotNull EnableBreakpointRule rule) { - final boolean removed = myBreakpointRules.remove(rule); - if (removed) { - rule.dispose(); - } - return removed; + //final boolean removed = myBreakpointRules.remove(rule); + //if (removed) { + // rule.dispose(); + //} + //return removed; + return false; } public boolean removeBreakpointRule(@NotNull Breakpoint slaveBreakpoint) { - for (final EnableBreakpointRule rule : myBreakpointRules) { - if (slaveBreakpoint.equals(rule.getSlaveBreakpoint())) { - removeBreakpointRule(rule); - return true; - } - } + //for (final EnableBreakpointRule rule : myBreakpointRules) { + // if (slaveBreakpoint.equals(rule.getSlaveBreakpoint())) { + // removeBreakpointRule(rule); + // return true; + // } + //} return false; } - private void updateBreakpointRules(@NotNull Breakpoint removedBreakpoint) { - for (Iterator<EnableBreakpointRule> it = myBreakpointRules.iterator(); it.hasNext();) { - final EnableBreakpointRule rule = it.next(); - if (removedBreakpoint.equals(rule.getMasterBreakpoint()) || removedBreakpoint.equals(rule.getSlaveBreakpoint())) { - it.remove(); - } - } - } + //private void updateBreakpointRules(@NotNull Breakpoint removedBreakpoint) { + // for (Iterator<EnableBreakpointRule> it = myBreakpointRules.iterator(); it.hasNext();) { + // final EnableBreakpointRule rule = it.next(); + // if (removedBreakpoint.equals(rule.getMasterBreakpoint()) || removedBreakpoint.equals(rule.getSlaveBreakpoint())) { + // it.remove(); + // } + // } + //} + // copied from XDebugSessionImpl processDependencies public void processBreakpointHit(@NotNull final Breakpoint breakpoint) { - for (final EnableBreakpointRule rule : myBreakpointRules) { - rule.processBreakpointHit(breakpoint); + XDependentBreakpointManager dependentBreakpointManager = ((XBreakpointManagerImpl)getXBreakpointManager()).getDependentBreakpointManager(); + XBreakpoint xBreakpoint = breakpoint.myXBreakpoint; + if (!dependentBreakpointManager.isMasterOrSlave(xBreakpoint)) { + return; } - } - - public void setInitialBreakpointsState() { - myAllowMulticasting = false; - for (final EnableBreakpointRule myBreakpointRule : myBreakpointRules) { - myBreakpointRule.init(); + List<XBreakpoint<?>> breakpoints = dependentBreakpointManager.getSlaveBreakpoints(xBreakpoint); + for (final XBreakpoint<?> slaveBreakpoint : breakpoints) { + DebuggerInvocationUtil.invokeLater(myProject, new Runnable() { + @Override + public void run() { + slaveBreakpoint.setEnabled(true); + } + }); } - myAllowMulticasting = true; - if (!myBreakpointRules.isEmpty()) { - IJSwingUtilities.invoke(new Runnable() { + + if (dependentBreakpointManager.getMasterBreakpoint(xBreakpoint) != null && !dependentBreakpointManager.isLeaveEnabled(xBreakpoint)) { + DebuggerInvocationUtil.invokeLater(myProject, new Runnable() { @Override public void run() { - myDispatcher.getMulticaster().breakpointsChanged(); + breakpoint.setEnabled(false); } }); + //myDebuggerManager.getBreakpointManager().getLineBreakpointManager().queueBreakpointUpdate(breakpoint); } } + + public void setInitialBreakpointsState() { + //myAllowMulticasting = false; + //for (final EnableBreakpointRule myBreakpointRule : myBreakpointRules) { + // myBreakpointRule.init(); + //} + //myAllowMulticasting = true; + //if (!myBreakpointRules.isEmpty()) { + // IJSwingUtilities.invoke(new Runnable() { + // @Override + // public void run() { + // myDispatcher.getMulticaster().breakpointsChanged(); + // } + // }); + //} + } @Nullable public Breakpoint findMasterBreakpoint(@NotNull Breakpoint dependentBreakpoint) { - for (final EnableBreakpointRule rule : myBreakpointRules) { - if (dependentBreakpoint.equals(rule.getSlaveBreakpoint())) { - return rule.getMasterBreakpoint(); - } - } - return null; + XDependentBreakpointManager dependentBreakpointManager = ((XBreakpointManagerImpl)getXBreakpointManager()).getDependentBreakpointManager(); + return myBreakpoints.get(dependentBreakpointManager.getMasterBreakpoint(dependentBreakpoint.myXBreakpoint)); } @Nullable public EnableBreakpointRule findBreakpointRule(@NotNull Breakpoint dependentBreakpoint) { - for (final EnableBreakpointRule rule : myBreakpointRules) { - if (dependentBreakpoint.equals(rule.getSlaveBreakpoint())) { - return rule; - } - } + //for (final EnableBreakpointRule rule : myBreakpointRules) { + // if (dependentBreakpoint.equals(rule.getSlaveBreakpoint())) { + // return rule; + // } + //} return null; } @@ -1076,4 +1056,14 @@ public class BreakpointManager { public String setProperty(String name, String value) { return myUIProperties.put(name, value); } + + public static PsiFile getPsiFile(XBreakpoint xBreakpoint, Project project) { + try { + final Document document = FileDocumentManager.getInstance().getDocument(xBreakpoint.getSourcePosition().getFile()); + return PsiDocumentManager.getInstance(project).getPsiFile(document); + } catch (Exception e) { + LOG.error(e); + } + return null; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java index d52044bbeb71..afeeb13aeb10 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java @@ -59,6 +59,9 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +/* + * Not used any more, since move to xBreakpoints + */ public abstract class BreakpointPropertiesPanel { private BreakpointChooser myMasterBreakpointChooser; @@ -208,8 +211,8 @@ public abstract class BreakpointPropertiesPanel { final ItemListener suspendPolicyChangeListener = new ItemListener() { @Override public void itemStateChanged(final ItemEvent e) { - final BreakpointDefaults defaults = getBreakpointManager(myProject).getBreakpointDefaults(breakpointCategory); - myMakeDefaultButton.setEnabled(!defaults.getSuspendPolicy().equals(getSelectedSuspendPolicy()) || defaults.isConditionEnabled() != myConditionCheckbox.isSelected()); + //final BreakpointDefaults defaults = getBreakpointManager(myProject).getBreakpointDefaults(breakpointCategory); + //myMakeDefaultButton.setEnabled(!defaults.getSuspendPolicy().equals(getSelectedSuspendPolicy()) || defaults.isConditionEnabled() != myConditionCheckbox.isSelected()); } }; @@ -426,13 +429,13 @@ public abstract class BreakpointPropertiesPanel { } private void updateSuspendPolicyRbFont() { - final String defPolicy = getBreakpointManager(myProject).getBreakpointDefaults(myBreakpointCategory).getSuspendPolicy(); + //final String defPolicy = getBreakpointManager(myProject).getBreakpointDefaults(myBreakpointCategory).getSuspendPolicy(); final Font font = myRbSuspendAll.getFont().deriveFont(Font.PLAIN); final Font boldFont = font.deriveFont(Font.BOLD); - myRbSuspendAll.setFont(DebuggerSettings.SUSPEND_ALL.equals(defPolicy)? boldFont : font); - myRbSuspendThread.setFont(DebuggerSettings.SUSPEND_THREAD.equals(defPolicy)? boldFont : font); + //myRbSuspendAll.setFont(DebuggerSettings.SUSPEND_ALL.equals(defPolicy)? boldFont : font); + //myRbSuspendThread.setFont(DebuggerSettings.SUSPEND_THREAD.equals(defPolicy)? boldFont : font); } protected ClassFilter createClassConditionFilter() { @@ -459,125 +462,126 @@ public abstract class BreakpointPropertiesPanel { * Init UI components with the values from Breakpoint */ public void initFrom(Breakpoint breakpoint, boolean moreOptionsVisible1) { - myBreakpoint = breakpoint; - boolean moreOptionsVisible = moreOptionsVisible1; - boolean actionsPanelVisible = moreOptionsVisible1; - - initMasterBreakpointPanel(); - - if (breakpoint.COUNT_FILTER > 0) { - myPassCountField.setText(Integer.toString(breakpoint.COUNT_FILTER)); - moreOptionsVisible = true; - } - else { - myPassCountField.setText(""); - } - - PsiElement context = breakpoint.getEvaluationElement(); - myPassCountCheckbox.setSelected(breakpoint.COUNT_FILTER_ENABLED); - - myConditionCheckbox.setSelected(breakpoint.CONDITION_ENABLED); - - myConditionCombo.setEnabled(breakpoint.CONDITION_ENABLED); - - myConditionCombo.setContext(context); - myConditionCombo.setText(breakpoint.getCondition() != null ? breakpoint.getCondition() : emptyText()); - - myCbSuspend.setSelected(breakpoint.SUSPEND); - myRbSuspendThread.setEnabled(myCbSuspend.isSelected()); - myRbSuspendAll.setEnabled(myCbSuspend.isSelected()); - - if(!breakpoint.SUSPEND) { - actionsPanelVisible = true; - } - if(DebuggerSettings.SUSPEND_THREAD.equals(breakpoint.SUSPEND_POLICY)){ - myRbSuspendThread.setSelected(true); - } - else { - myRbSuspendAll.setSelected(true); - } - - myCbSuspend.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (!myActionsPanel.isVisible()) { - if (!myCbSuspend.isSelected()) { - if (myDelegate != null) { - myDelegate.showActionsPanel(); - } - } - } - myRbSuspendThread.setEnabled(myCbSuspend.isSelected()); - myRbSuspendAll.setEnabled(myCbSuspend.isSelected()); - } - }); - myLogMessageCheckBox.setSelected(breakpoint.LOG_ENABLED); - myTemporaryCheckBox.setSelected(breakpoint.REMOVE_AFTER_HIT); - myEnabledCheckbox.setSelected(breakpoint.ENABLED); - myEnabledCheckbox.setText(breakpoint.getShortName() + " enabled"); - - DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().addBreakpointManagerListener(new BreakpointManagerListener() { - @Override - public void breakpointsChanged() { - myEnabledCheckbox.setSelected(myBreakpoint.ENABLED); - } - }); - - myEnabledCheckbox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (myBreakpoint.ENABLED != myEnabledCheckbox.isSelected()) { - myBreakpoint.ENABLED = myEnabledCheckbox.isSelected(); - getBreakpointManager(myProject).fireBreakpointChanged(myBreakpoint); - myBreakpoint.updateUI(); - } - } - }); - myTemporaryCheckBox.setVisible(breakpoint instanceof LineBreakpoint); - myLogExpressionCheckBox.setSelected(breakpoint.LOG_EXPRESSION_ENABLED); - if (breakpoint.LOG_ENABLED || breakpoint.LOG_EXPRESSION_ENABLED || (breakpoint instanceof LineBreakpoint && breakpoint.REMOVE_AFTER_HIT)) { - actionsPanelVisible = true; - } - - myLogExpressionCombo.setContext(context); - - if (breakpoint.getLogMessage() != null) { - myLogExpressionCombo.setText(breakpoint.getLogMessage()); - } - else { - myLogExpressionCombo.setText(emptyText()); - } - - myLogExpressionCombo.setEnabled(breakpoint.LOG_EXPRESSION_ENABLED); - if (breakpoint.LOG_EXPRESSION_ENABLED) { - actionsPanelVisible = true; - } - - myInstanceFiltersCheckBox.setSelected(breakpoint.INSTANCE_FILTERS_ENABLED); - myInstanceFiltersField.setEnabled(breakpoint.INSTANCE_FILTERS_ENABLED); - myInstanceFiltersField.getTextField().setEditable(breakpoint.INSTANCE_FILTERS_ENABLED); - myInstanceFilters = breakpoint.getInstanceFilters(); - updateInstanceFilterEditor(true); - if (breakpoint.INSTANCE_FILTERS_ENABLED) { - moreOptionsVisible = true; - } - - myClassFiltersCheckBox.setSelected(breakpoint.CLASS_FILTERS_ENABLED); - myClassFiltersField.setEnabled(breakpoint.CLASS_FILTERS_ENABLED); - myClassFiltersField.getTextField().setEditable(breakpoint.CLASS_FILTERS_ENABLED); - myClassFilters = breakpoint.getClassFilters(); - myClassExclusionFilters = breakpoint.getClassExclusionFilters(); - updateClassFilterEditor(true); - if (breakpoint.CLASS_FILTERS_ENABLED) { - moreOptionsVisible = true; - } - - myBreakpointPsiClass = breakpoint.getPsiClass(); - - updateCheckboxes(); - - setActionsPanelVisible(actionsPanelVisible && !moreOptionsVisible1); - setMoreOptionsVisible(moreOptionsVisible); + //myBreakpoint = breakpoint; + //boolean moreOptionsVisible = moreOptionsVisible1; + //boolean actionsPanelVisible = moreOptionsVisible1; + // + //initMasterBreakpointPanel(); + // + //if (breakpoint.getCountFilter() > 0) { + // myPassCountField.setText(Integer.toString(breakpoint.getCountFilter())); + // moreOptionsVisible = true; + //} + //else { + // myPassCountField.setText(""); + //} + // + //PsiElement context = breakpoint.getEvaluationElement(); + //myPassCountCheckbox.setSelected(breakpoint.isCountFilterEnabled()); + // + //myConditionCheckbox.setSelected(breakpoint.isConditionEnabled()); + // + //myConditionCombo.setEnabled(breakpoint.isConditionEnabled()); + // + //myConditionCombo.setContext(context); + //myConditionCombo.setText(breakpoint.getCondition() != null ? breakpoint.getCondition() : emptyText()); + // + //myCbSuspend.setSelected(breakpoint.isSuspend()); + //myRbSuspendThread.setEnabled(myCbSuspend.isSelected()); + //myRbSuspendAll.setEnabled(myCbSuspend.isSelected()); + // + //if(!breakpoint.isSuspend()) { + // actionsPanelVisible = true; + //} + //if(DebuggerSettings.SUSPEND_THREAD.equals(breakpoint.getSuspendPolicy())){ + // myRbSuspendThread.setSelected(true); + //} + //else { + // myRbSuspendAll.setSelected(true); + //} + // + //myCbSuspend.addActionListener(new ActionListener() { + // @Override + // public void actionPerformed(ActionEvent event) { + // if (!myActionsPanel.isVisible()) { + // if (!myCbSuspend.isSelected()) { + // if (myDelegate != null) { + // myDelegate.showActionsPanel(); + // } + // } + // } + // myRbSuspendThread.setEnabled(myCbSuspend.isSelected()); + // myRbSuspendAll.setEnabled(myCbSuspend.isSelected()); + // } + //}); + //myLogMessageCheckBox.setSelected(breakpoint.isLogEnabled()); + //myTemporaryCheckBox.setSelected(breakpoint.isRemoveAfterHit()); + //myEnabledCheckbox.setSelected(breakpoint.isEnabled()); + //myEnabledCheckbox.setText(breakpoint.getShortName() + " enabled"); + // + //DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().addBreakpointManagerListener(new BreakpointManagerListener() { + // @Override + // public void breakpointsChanged() { + // myEnabledCheckbox.setSelected(myBreakpoint.isEnabled()); + // } + //}); + // + //myEnabledCheckbox.addActionListener(new ActionListener() { + // @Override + // public void actionPerformed(ActionEvent event) { + // if (myBreakpoint.isEnabled() != myEnabledCheckbox.isSelected()) { + // myBreakpoint.setEnabled(myEnabledCheckbox.isSelected()); + // getBreakpointManager(myProject).fireBreakpointChanged(myBreakpoint); + // myBreakpoint.updateUI(); + // } + // } + //}); + //myTemporaryCheckBox.setVisible(breakpoint instanceof LineBreakpoint); + //myLogExpressionCheckBox.setSelected(breakpoint.isLogExpressionEnabled()); + //if (breakpoint.isLogEnabled() || + // breakpoint.isLogExpressionEnabled() || (breakpoint instanceof LineBreakpoint && breakpoint.isRemoveAfterHit())) { + // actionsPanelVisible = true; + //} + // + //myLogExpressionCombo.setContext(context); + // + //if (breakpoint.getLogMessage() != null) { + // myLogExpressionCombo.setText(breakpoint.getLogMessage()); + //} + //else { + // myLogExpressionCombo.setText(emptyText()); + //} + // + //myLogExpressionCombo.setEnabled(breakpoint.isLogExpressionEnabled()); + //if (breakpoint.isLogExpressionEnabled()) { + // actionsPanelVisible = true; + //} + // + //myInstanceFiltersCheckBox.setSelected(breakpoint.isInstanceFiltersEnabled()); + //myInstanceFiltersField.setEnabled(breakpoint.isInstanceFiltersEnabled()); + //myInstanceFiltersField.getTextField().setEditable(breakpoint.isInstanceFiltersEnabled()); + //myInstanceFilters = breakpoint.getInstanceFilters(); + //updateInstanceFilterEditor(true); + //if (breakpoint.isInstanceFiltersEnabled()) { + // moreOptionsVisible = true; + //} + // + //myClassFiltersCheckBox.setSelected(breakpoint.isClassFiltersEnabled()); + //myClassFiltersField.setEnabled(breakpoint.isClassFiltersEnabled()); + //myClassFiltersField.getTextField().setEditable(breakpoint.isClassFiltersEnabled()); + //myClassFilters = breakpoint.getClassFilters(); + //myClassExclusionFilters = breakpoint.getClassExclusionFilters(); + //updateClassFilterEditor(true); + //if (breakpoint.isClassFiltersEnabled()) { + // moreOptionsVisible = true; + //} + // + //myBreakpointPsiClass = breakpoint.getPsiClass(); + // + //updateCheckboxes(); + // + //setActionsPanelVisible(actionsPanelVisible && !moreOptionsVisible1); + //setMoreOptionsVisible(moreOptionsVisible); } private void initMasterBreakpointPanel() { @@ -632,41 +636,41 @@ public abstract class BreakpointPropertiesPanel { */ public void saveTo(Breakpoint breakpoint) { - saveMasterBreakpoint(); - try { - String text = myPassCountField.getText().trim(); - breakpoint.COUNT_FILTER = !text.isEmpty() ? Integer.parseInt(text) : 0; - if (breakpoint.COUNT_FILTER < 0) { - breakpoint.COUNT_FILTER = 0; - } - } - catch (Exception ignored) { - } - - breakpoint.COUNT_FILTER_ENABLED = breakpoint.COUNT_FILTER > 0 && myPassCountCheckbox.isSelected(); - breakpoint.setCondition(myConditionCombo.getText()); - breakpoint.CONDITION_ENABLED = myConditionCheckbox.isSelected(); - breakpoint.setLogMessage(myLogExpressionCombo.getText()); - breakpoint.LOG_EXPRESSION_ENABLED = !breakpoint.getLogMessage().isEmpty() && myLogExpressionCheckBox.isSelected(); - breakpoint.LOG_ENABLED = myLogMessageCheckBox.isSelected(); - breakpoint.ENABLED = myEnabledCheckbox.isSelected(); - breakpoint.REMOVE_AFTER_HIT = myTemporaryCheckBox.isSelected(); - breakpoint.SUSPEND = myCbSuspend.isSelected(); - breakpoint.SUSPEND_POLICY = getSelectedSuspendPolicy(); - reloadInstanceFilters(); - reloadClassFilters(); - updateInstanceFilterEditor(true); - updateClassFilterEditor(true); - - breakpoint.INSTANCE_FILTERS_ENABLED = myInstanceFiltersField.getText().length() > 0 && myInstanceFiltersCheckBox.isSelected(); - breakpoint.CLASS_FILTERS_ENABLED = myClassFiltersField.getText().length() > 0 && myClassFiltersCheckBox.isSelected(); - breakpoint.setClassFilters(myClassFilters); - breakpoint.setClassExclusionFilters(myClassExclusionFilters); - breakpoint.setInstanceFilters(myInstanceFilters); - - myConditionCombo.addRecent(myConditionCombo.getText()); - myLogExpressionCombo.addRecent(myLogExpressionCombo.getText()); - breakpoint.updateUI(); + //saveMasterBreakpoint(); + //try { + // String text = myPassCountField.getText().trim(); + // breakpoint.setCountFilter(!text.isEmpty() ? Integer.parseInt(text) : 0); + // if (breakpoint.getCountFilter() < 0) { + // breakpoint.setCountFilter(0); + // } + //} + //catch (Exception ignored) { + //} + // + //breakpoint.setCountFilterEnabled(breakpoint.getCountFilter() > 0 && myPassCountCheckbox.isSelected()); + //breakpoint.setCondition(myConditionCombo.getText().getText()); + ////breakpoint.setConditionEnabled(myConditionCheckbox.isSelected()); + //breakpoint.setLogMessage(myLogExpressionCombo.getText()); + //breakpoint.setLogExpressionEnabled(!breakpoint.getLogMessage().isEmpty() && myLogExpressionCheckBox.isSelected()); + //breakpoint.setLogEnabled(myLogMessageCheckBox.isSelected()); + //breakpoint.setEnabled(myEnabledCheckbox.isSelected()); + //breakpoint.setRemoveAfterHit(myTemporaryCheckBox.isSelected()); + ////breakpoint.setSuspend(myCbSuspend.isSelected()); + //breakpoint.setSuspendPolicy(getSelectedSuspendPolicy()); + //reloadInstanceFilters(); + //reloadClassFilters(); + //updateInstanceFilterEditor(true); + //updateClassFilterEditor(true); + // + //breakpoint.setInstanceFiltersEnabled(myInstanceFiltersField.getText().length() > 0 && myInstanceFiltersCheckBox.isSelected()); + //breakpoint.setClassFiltersEnabled(myClassFiltersField.getText().length() > 0 && myClassFiltersCheckBox.isSelected()); + //breakpoint.setClassFilters(myClassFilters); + //breakpoint.setClassExclusionFilters(myClassExclusionFilters); + //breakpoint.setInstanceFilters(myInstanceFilters); + // + //myConditionCombo.addRecent(myConditionCombo.getText()); + //myLogExpressionCombo.addRecent(myLogExpressionCombo.getText()); + //breakpoint.updateUI(); } private static String concatWithEx(List<String> s, String concator, int N, String NthConcator) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java index 16b75279099e..8cd1bfbe8151 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java @@ -25,49 +25,49 @@ import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.debugger.ui.JavaDebuggerSupport; -import com.intellij.openapi.actionSystem.ActionGroup; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.impl.DocumentMarkupModel; -import com.intellij.openapi.editor.markup.*; +import com.intellij.openapi.editor.markup.MarkupEditorFilterFactory; +import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.jsp.JspFile; -import com.intellij.ui.AppUIUtil; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.util.StringBuilderSpinAllocator; -import com.intellij.xdebugger.impl.DebuggerSupport; -import com.intellij.xdebugger.impl.actions.EditBreakpointAction; +import com.intellij.xdebugger.XDebuggerManager; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.XBreakpointManager; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.intellij.xdebugger.ui.DebuggerColors; import com.intellij.xml.util.XmlStringUtil; import com.sun.jdi.ReferenceType; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; import javax.swing.*; -import java.awt.*; -import java.awt.dnd.DragSource; /** * User: lex * Date: Sep 2, 2003 * Time: 3:22:55 PM */ -public abstract class BreakpointWithHighlighter extends Breakpoint { +public abstract class BreakpointWithHighlighter<P extends JavaBreakpointProperties> extends Breakpoint<P> { @Nullable private RangeHighlighter myHighlighter; @@ -150,7 +150,7 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { private Icon calcIcon(@Nullable DebugProcessImpl debugProcess) { final boolean muted = debugProcess != null && isMuted(debugProcess); - if (!ENABLED) { + if (!isEnabled()) { return getDisabledIcon(muted); } @@ -184,13 +184,14 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { return getSetIcon(muted); } - protected BreakpointWithHighlighter(@NotNull Project project) { + protected BreakpointWithHighlighter(@NotNull Project project, XBreakpoint xBreakpoint) { //for persistency - super(project); + super(project, xBreakpoint); + reload(); } - public BreakpointWithHighlighter(@NotNull final Project project, @NotNull final RangeHighlighter highlighter) { - super(project); + public BreakpointWithHighlighter(@NotNull final Project project, @NotNull final RangeHighlighter highlighter, XBreakpoint breakpoint) { + super(project, breakpoint); myHighlighter = highlighter; setEditorFilter(highlighter); reload(); @@ -208,10 +209,10 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { @Override public boolean isValid() { - return isPositionValid(getSourcePosition()); + return isPositionValid(myXBreakpoint.getSourcePosition()); } - private static boolean isPositionValid(@Nullable final SourcePosition sourcePosition) { + protected static boolean isPositionValid(@Nullable final XSourcePosition sourcePosition) { return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { @@ -238,34 +239,34 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { } buf.append(" <br> "); buf.append(DebuggerBundle.message("breakpoint.property.name.suspend.policy")).append(" : "); - if (DebuggerSettings.SUSPEND_NONE.equals(SUSPEND_POLICY) || !SUSPEND) { + if (DebuggerSettings.SUSPEND_NONE.equals(getSuspendPolicy()) || !isSuspend()) { buf.append(DebuggerBundle.message("breakpoint.properties.panel.option.suspend.none")); } - else if (DebuggerSettings.SUSPEND_ALL.equals(SUSPEND_POLICY)) { + else if (DebuggerSettings.SUSPEND_ALL.equals(getSuspendPolicy())) { buf.append(DebuggerBundle.message("breakpoint.properties.panel.option.suspend.all")); } - else if (DebuggerSettings.SUSPEND_THREAD.equals(SUSPEND_POLICY)) { + else if (DebuggerSettings.SUSPEND_THREAD.equals(getSuspendPolicy())) { buf.append(DebuggerBundle.message("breakpoint.properties.panel.option.suspend.thread")); } buf.append(" <br> "); buf.append(DebuggerBundle.message("breakpoint.property.name.log.message")).append(": "); - buf.append(LOG_ENABLED ? CommonBundle.getYesButtonText() : CommonBundle.getNoButtonText()); - if (LOG_EXPRESSION_ENABLED) { + buf.append(isLogEnabled() ? CommonBundle.getYesButtonText() : CommonBundle.getNoButtonText()); + if (isLogExpressionEnabled()) { buf.append(" <br> "); buf.append(DebuggerBundle.message("breakpoint.property.name.log.expression")).append(": "); buf.append(XmlStringUtil.escapeString(getLogMessage().getText())); } - if (CONDITION_ENABLED && getCondition() != null && getCondition().getText() != null && !getCondition().getText().isEmpty()) { + if (isConditionEnabled() && getCondition() != null && getCondition().getText() != null && !getCondition().getText().isEmpty()) { buf.append(" <br> "); buf.append(DebuggerBundle.message("breakpoint.property.name.condition")).append(": "); buf.append(XmlStringUtil.escapeString(getCondition().getText())); } - if (COUNT_FILTER_ENABLED) { + if (isCountFilterEnabled()) { buf.append(" <br> "); buf.append(DebuggerBundle.message("breakpoint.property.name.pass.count")).append(": "); - buf.append(COUNT_FILTER); + buf.append(getCountFilter()); } - if (CLASS_FILTERS_ENABLED) { + if (isClassFiltersEnabled()) { buf.append(" <br> "); buf.append(DebuggerBundle.message("breakpoint.property.name.class.filters")).append(": "); ClassFilter[] classFilters = getClassFilters(); @@ -273,7 +274,7 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { buf.append(classFilter.getPattern()).append(" "); } } - if (INSTANCE_FILTERS_ENABLED) { + if (isInstanceFiltersEnabled()) { buf.append(" <br> "); buf.append(DebuggerBundle.message("breakpoint.property.name.instance.filters")); InstanceFilter[] instanceFilters = getInstanceFilters(); @@ -290,25 +291,23 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { } @Override - public final void reload() { + public void reload() { ApplicationManager.getApplication().assertReadAccessAllowed(); - RangeHighlighter highlighter = myHighlighter; - if (highlighter != null && highlighter.isValid()) { - PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(highlighter.getDocument()); - if (psiFile != null) { - mySourcePosition = SourcePosition.createFromOffset(psiFile, highlighter.getStartOffset()); - reload(psiFile); - return; - } + final XSourcePosition position = myXBreakpoint.getSourcePosition(); + try { + final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(position.getFile()); + mySourcePosition = SourcePosition.createFromOffset(psiFile, position.getOffset()); + } catch (Exception e) { + mySourcePosition = null; } - mySourcePosition = null; + reload(BreakpointManager.getPsiFile(myXBreakpoint, myProject)); } @Override public void createRequest(@NotNull DebugProcessImpl debugProcess) { DebuggerManagerThreadImpl.assertIsManagerThread(); // check is this breakpoint is enabled, vm reference is valid and there're no requests created yet - if (!ENABLED || + if (!isEnabled() || !debugProcess.isAttached() || isMuted(debugProcess) || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { @@ -329,7 +328,7 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { @Override public void processClassPrepare(final DebugProcess debugProcess, final ReferenceType classType) { - if (!ENABLED || !isValid()) { + if (!isEnabled() || !isValid()) { return; } createRequestForPreparedClass((DebugProcessImpl)debugProcess, classType); @@ -383,20 +382,24 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { private void updateGutter() { if (myVisible) { - RangeHighlighter highlighter = myHighlighter; - if (highlighter != null && highlighter.isValid() && isValid()) { - AppUIUtil.invokeLaterIfProjectAlive(myProject, new Runnable() { - @Override - public void run() { - if (isValid()) { - setupGutterRenderer(myHighlighter); - } - } - }); - } - else { - DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().removeBreakpoint(this); + if (isValid()) { + final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(myProject).getBreakpointManager(); + breakpointManager.updateBreakpointPresentation((XLineBreakpoint)myXBreakpoint, getIcon(), null); } + //RangeHighlighter highlighter = myHighlighter; + //if (highlighter != null && highlighter.isValid() && isValid()) { + // AppUIUtil.invokeLaterIfProjectAlive(myProject, new Runnable() { + // @Override + // public void run() { + // if (isValid()) { + // setupGutterRenderer(myHighlighter); + // } + // } + // }); + //} + //else { + // DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().removeBreakpoint(this); + //} } } @@ -422,11 +425,10 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { } public boolean isAt(@NotNull Document document, int offset) { - RangeHighlighter highlighter = getHighlighter(); - return highlighter != null && - highlighter.isValid() && - document.equals(highlighter.getDocument()) && - getSourcePosition().getLine() == document.getLineNumber(offset); + final VirtualFile file = FileDocumentManager.getInstance().getFile(document); + int line = document.getLineNumber(offset); + XSourcePosition position = myXBreakpoint.getSourcePosition(); + return position != null && position.getLine() == line && position.getFile().equals(file); } protected void reload(PsiFile psiFile) { @@ -448,9 +450,9 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { }); } - private void setupGutterRenderer(@NotNull RangeHighlighter highlighter) { - highlighter.setGutterIconRenderer(new MyGutterIconRenderer(getIcon(), getDescription())); - } + //private void setupGutterRenderer(@NotNull RangeHighlighter highlighter) { + // highlighter.setGutterIconRenderer(new MyGutterIconRenderer(getIcon(), getDescription())); + //} @Override public abstract Key<? extends BreakpointWithHighlighter> getCategory(); @@ -559,7 +561,7 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { public void readExternal(@NotNull Element breakpointNode) throws InvalidDataException { super.readExternal(breakpointNode); //noinspection HardCodedStringLiteral - final String url = breakpointNode.getAttributeValue("url"); + //final String url = breakpointNode.getAttributeValue("url"); //noinspection HardCodedStringLiteral final String className = breakpointNode.getAttributeValue("class"); @@ -573,146 +575,146 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { myPackageName = packageName; } - VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url); - if (vFile == null) { - throw new InvalidDataException(DebuggerBundle.message("error.breakpoint.file.not.found", url)); - } - final Document doc = FileDocumentManager.getInstance().getDocument(vFile); - if (doc == null) { - throw new InvalidDataException(DebuggerBundle.message("error.cannot.load.breakpoint.file", url)); - } - - // line number - final int line; - try { - //noinspection HardCodedStringLiteral - line = Integer.parseInt(breakpointNode.getAttributeValue("line")); - } - catch (Exception e) { - throw new InvalidDataException("Line number is invalid for breakpoint"); - } - if (line < 0) { - throw new InvalidDataException("Line number is invalid for breakpoint"); - } - - RangeHighlighter highlighter = createHighlighter(myProject, doc, line); - - if (highlighter == null) { - throw new InvalidDataException(""); - } - - myHighlighter = highlighter; - reload(); - } - - @Override - @SuppressWarnings({"HardCodedStringLiteral"}) - public void writeExternal(@NotNull Element parentNode) throws WriteExternalException { - super.writeExternal(parentNode); - PsiFile psiFile = getSourcePosition().getFile(); - final VirtualFile virtualFile = psiFile.getVirtualFile(); - final String url = virtualFile != null ? virtualFile.getUrl() : ""; - parentNode.setAttribute("url", url); - parentNode.setAttribute("line", Integer.toString(getSourcePosition().getLine())); - if (myClassName != null) { - parentNode.setAttribute("class", myClassName); - } - if (myPackageName != null) { - parentNode.setAttribute("package", myPackageName); - } - } - - private class MyGutterIconRenderer extends GutterIconRenderer { - private final Icon myIcon; - private final String myDescription; - - public MyGutterIconRenderer(@NotNull Icon icon, @NotNull String description) { - myIcon = icon; - myDescription = description; - } - - @Override - @NotNull - public Icon getIcon() { - return myIcon; - } - - @Override - public String getTooltipText() { - return myDescription; - } - - @Override - public Alignment getAlignment() { - return Alignment.RIGHT; - } - - @Override - public AnAction getClickAction() { - return new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().removeBreakpoint(BreakpointWithHighlighter.this); - } - }; - } - - @Override - public AnAction getMiddleButtonClickAction() { - return new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - ENABLED = !ENABLED; - DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().fireBreakpointChanged(BreakpointWithHighlighter.this); - updateUI(); - } - }; - } - - @Override - public ActionGroup getPopupMenuActions() { - return null; - } - - @Nullable - @Override - public AnAction getRightButtonClickAction() { - return new EditBreakpointAction.ContextAction(this, BreakpointWithHighlighter.this, DebuggerSupport.getDebuggerSupport(JavaDebuggerSupport.class)); - } - - @Override - public GutterDraggableObject getDraggableObject() { - return new GutterDraggableObject() { - @Override - public boolean copy(int line, @NotNull VirtualFile file) { - final PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file); - return psiFile != null && moveTo(SourcePosition.createFromLine(psiFile, line)); - } - - @Override - public Cursor getCursor(int line) { - final SourcePosition newPosition = SourcePosition.createFromLine(getSourcePosition().getFile(), line); - return canMoveTo(newPosition) ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop; - } - }; - } - - @Override - public boolean equals(@NotNull Object obj) { - return obj instanceof MyGutterIconRenderer && - Comparing.equal(getTooltipText(), ((MyGutterIconRenderer)obj).getTooltipText()) && - Comparing.equal(getIcon(), ((MyGutterIconRenderer)obj).getIcon()); - } - - @Override - public int hashCode() { - return getIcon().hashCode(); - } - - @Override - public String toString() { - return "LB " + getDisplayName(); - } - } + //VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url); + //if (vFile == null) { + // throw new InvalidDataException(DebuggerBundle.message("error.breakpoint.file.not.found", url)); + //} + //final Document doc = FileDocumentManager.getInstance().getDocument(vFile); + //if (doc == null) { + // throw new InvalidDataException(DebuggerBundle.message("error.cannot.load.breakpoint.file", url)); + //} + // + //// line number + //final int line; + //try { + // //noinspection HardCodedStringLiteral + // line = Integer.parseInt(breakpointNode.getAttributeValue("line")); + //} + //catch (Exception e) { + // throw new InvalidDataException("Line number is invalid for breakpoint"); + //} + //if (line < 0) { + // throw new InvalidDataException("Line number is invalid for breakpoint"); + //} + // + //RangeHighlighter highlighter = createHighlighter(myProject, doc, line); + // + //if (highlighter == null) { + // throw new InvalidDataException(""); + //} + // + //myHighlighter = highlighter; + //reload(); + } + // + //@Override + //@SuppressWarnings({"HardCodedStringLiteral"}) + //public void writeExternal(@NotNull Element parentNode) throws WriteExternalException { + // super.writeExternal(parentNode); + // PsiFile psiFile = getSourcePosition().getFile(); + // final VirtualFile virtualFile = psiFile.getVirtualFile(); + // final String url = virtualFile != null ? virtualFile.getUrl() : ""; + // parentNode.setAttribute("url", url); + // parentNode.setAttribute("line", Integer.toString(getSourcePosition().getLine())); + // if (myClassName != null) { + // parentNode.setAttribute("class", myClassName); + // } + // if (myPackageName != null) { + // parentNode.setAttribute("package", myPackageName); + // } + //} + + //private class MyGutterIconRenderer extends GutterIconRenderer { + // private final Icon myIcon; + // private final String myDescription; + // + // public MyGutterIconRenderer(@NotNull Icon icon, @NotNull String description) { + // myIcon = icon; + // myDescription = description; + // } + // + // @Override + // @NotNull + // public Icon getIcon() { + // return myIcon; + // } + // + // @Override + // public String getTooltipText() { + // return myDescription; + // } + // + // @Override + // public Alignment getAlignment() { + // return Alignment.RIGHT; + // } + // + // @Override + // public AnAction getClickAction() { + // return new AnAction() { + // @Override + // public void actionPerformed(AnActionEvent e) { + // DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().removeBreakpoint(BreakpointWithHighlighter.this); + // } + // }; + // } + // + // @Override + // public AnAction getMiddleButtonClickAction() { + // return new AnAction() { + // @Override + // public void actionPerformed(AnActionEvent e) { + // setEnabled(!isEnabled()); + // DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().fireBreakpointChanged(BreakpointWithHighlighter.this); + // updateUI(); + // } + // }; + // } + // + // @Override + // public ActionGroup getPopupMenuActions() { + // return null; + // } + // + // @Nullable + // @Override + // public AnAction getRightButtonClickAction() { + // return new EditBreakpointAction.ContextAction(this, BreakpointWithHighlighter.this, DebuggerSupport.getDebuggerSupport(JavaDebuggerSupport.class)); + // } + // + // @Override + // public GutterDraggableObject getDraggableObject() { + // return new GutterDraggableObject() { + // @Override + // public boolean copy(int line, @NotNull VirtualFile file) { + // final PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file); + // return psiFile != null && moveTo(SourcePosition.createFromLine(psiFile, line)); + // } + // + // @Override + // public Cursor getCursor(int line) { + // final SourcePosition newPosition = SourcePosition.createFromLine(getSourcePosition().getFile(), line); + // return canMoveTo(newPosition) ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop; + // } + // }; + // } + // + // @Override + // public boolean equals(@NotNull Object obj) { + // return obj instanceof MyGutterIconRenderer && + // Comparing.equal(getTooltipText(), ((MyGutterIconRenderer)obj).getTooltipText()) && + // Comparing.equal(getIcon(), ((MyGutterIconRenderer)obj).getIcon()); + // } + // + // @Override + // public int hashCode() { + // return getIcon().hashCode(); + // } + // + // @Override + // public String toString() { + // return "LB " + getDisplayName(); + // } + //} } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java index c6a19557f4e8..8a0b5159d5f7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java @@ -34,13 +34,14 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.Location; import com.sun.jdi.ObjectReference; @@ -50,36 +51,32 @@ import com.sun.jdi.event.LocatableEvent; import com.sun.jdi.request.ExceptionRequest; import org.jdom.Element; import org.jetbrains.annotations.NonNls; +import org.jetbrains.java.debugger.breakpoints.properties.JavaExceptionBreakpointProperties; import javax.swing.*; -public class ExceptionBreakpoint extends Breakpoint { +public class ExceptionBreakpoint extends Breakpoint<JavaExceptionBreakpointProperties> { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.ExceptionBreakpoint"); - public boolean NOTIFY_CAUGHT = true; - public boolean NOTIFY_UNCAUGHT = true; - private String myQualifiedName; - private String myPackageName; - protected final static String READ_NO_CLASS_NAME = DebuggerBundle.message("error.absent.exception.breakpoint.class.name"); public static final @NonNls Key<ExceptionBreakpoint> CATEGORY = BreakpointCategory.lookup("exception_breakpoints"); - public ExceptionBreakpoint(Project project) { - super(project); + public ExceptionBreakpoint(Project project, XBreakpoint xBreakpoint) { + super(project, xBreakpoint); } public Key<? extends ExceptionBreakpoint> getCategory() { return CATEGORY; } - protected ExceptionBreakpoint(Project project, String qualifiedName, String packageName) { - super(project); - myQualifiedName = qualifiedName; + protected ExceptionBreakpoint(Project project, String qualifiedName, String packageName, XBreakpoint xBreakpoint) { + super(project, xBreakpoint); + setQualifiedName(qualifiedName); if (packageName == null) { - myPackageName = calcPackageName(qualifiedName); + setPackageName(calcPackageName(qualifiedName)); } else { - myPackageName = packageName; + setPackageName(packageName); } } @@ -92,27 +89,27 @@ public class ExceptionBreakpoint extends Breakpoint { } public String getClassName() { - return myQualifiedName; + return getQualifiedName(); } public String getPackageName() { - return myPackageName; + return getProperties().myPackageName; } public PsiClass getPsiClass() { return PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(new Computable<PsiClass>() { public PsiClass compute() { - return myQualifiedName != null ? DebuggerUtilsEx.findClass(myQualifiedName, myProject, GlobalSearchScope.allScope(myProject)) : null; + return getQualifiedName() != null ? DebuggerUtilsEx.findClass(getQualifiedName(), myProject, GlobalSearchScope.allScope(myProject)) : null; } }); } public String getDisplayName() { - return DebuggerBundle.message("breakpoint.exception.breakpoint.display.name", myQualifiedName); + return DebuggerBundle.message("breakpoint.exception.breakpoint.display.name", getQualifiedName()); } public Icon getIcon() { - if (!ENABLED) { + if (!isEnabled()) { final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this); return master == null? AllIcons.Debugger.Db_disabled_exception_breakpoint : AllIcons.Debugger.Db_dep_exception_breakpoint; } @@ -124,20 +121,20 @@ public class ExceptionBreakpoint extends Breakpoint { public void createRequest(final DebugProcessImpl debugProcess) { DebuggerManagerThreadImpl.assertIsManagerThread(); - if (!ENABLED || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { + if (!isEnabled() || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { return; } SourcePosition classPosition = PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(new Computable<SourcePosition>() { public SourcePosition compute() { - PsiClass psiClass = DebuggerUtilsEx.findClass(myQualifiedName, myProject, debugProcess.getSearchScope()); + PsiClass psiClass = DebuggerUtilsEx.findClass(getQualifiedName(), myProject, debugProcess.getSearchScope()); return psiClass != null ? SourcePosition.createFromElement(psiClass) : null; } }); if(classPosition == null) { - createOrWaitPrepare(debugProcess, myQualifiedName); + createOrWaitPrepare(debugProcess, getQualifiedName()); } else { createOrWaitPrepare(debugProcess, classPosition); @@ -146,11 +143,12 @@ public class ExceptionBreakpoint extends Breakpoint { public void processClassPrepare(DebugProcess process, ReferenceType refType) { DebugProcessImpl debugProcess = (DebugProcessImpl)process; - if (!ENABLED) { + if (!isEnabled()) { return; } // trying to create a request - ExceptionRequest request = debugProcess.getRequestsManager().createExceptionRequest(this, refType, NOTIFY_CAUGHT, NOTIFY_UNCAUGHT); + ExceptionRequest request = debugProcess.getRequestsManager().createExceptionRequest(this, refType, isNotifyCaught(), + isNotifyUncaught()); debugProcess.getRequestsManager().enableRequest(request); if (LOG.isDebugEnabled()) { if (refType != null) { @@ -170,7 +168,7 @@ public class ExceptionBreakpoint extends Breakpoint { } public String getEventMessage(LocatableEvent event) { - String exceptionName = (myQualifiedName != null)? myQualifiedName : "java.lang.Throwable"; + String exceptionName = (getQualifiedName() != null)? getQualifiedName() : "java.lang.Throwable"; String threadName = null; if (event instanceof ExceptionEvent) { ExceptionEvent exceptionEvent = (ExceptionEvent)event; @@ -216,15 +214,15 @@ public class ExceptionBreakpoint extends Breakpoint { return true; } - @SuppressWarnings({"HardCodedStringLiteral"}) public void writeExternal(Element parentNode) throws WriteExternalException { - super.writeExternal(parentNode); - if(myQualifiedName != null) { - parentNode.setAttribute("class_name", myQualifiedName); - } - if(myPackageName != null) { - parentNode.setAttribute("package_name", myPackageName); - } - } + //@SuppressWarnings({"HardCodedStringLiteral"}) public void writeExternal(Element parentNode) throws WriteExternalException { + // super.writeExternal(parentNode); + // if(getQualifiedName() != null) { + // parentNode.setAttribute("class_name", getQualifiedName()); + // } + // if(getPackageName() != null) { + // parentNode.setAttribute("package_name", getPackageName()); + // } + //} public PsiElement getEvaluationElement() { if (getClassName() == null) { @@ -235,16 +233,45 @@ public class ExceptionBreakpoint extends Breakpoint { public void readExternal(Element parentNode) throws InvalidDataException { super.readExternal(parentNode); + + //noinspection HardCodedStringLiteral + String packageName = parentNode.getAttributeValue("package_name"); + setPackageName(packageName != null? packageName : calcPackageName(packageName)); + + try { + getProperties().NOTIFY_CAUGHT = Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "NOTIFY_CAUGHT")); + } catch (Exception e) { + } + try { + getProperties().NOTIFY_UNCAUGHT = Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "NOTIFY_UNCAUGHT")); + } catch (Exception e) { + } + //noinspection HardCodedStringLiteral String className = parentNode.getAttributeValue("class_name"); - myQualifiedName = className; + setQualifiedName(className); if(className == null) { throw new InvalidDataException(READ_NO_CLASS_NAME); } + } - //noinspection HardCodedStringLiteral - String packageName = parentNode.getAttributeValue("package_name"); - myPackageName = packageName != null? packageName : calcPackageName(packageName); + private boolean isNotifyCaught() { + return getProperties().NOTIFY_CAUGHT; + } + + private boolean isNotifyUncaught() { + return getProperties().NOTIFY_UNCAUGHT; } + private String getQualifiedName() { + return getProperties().myQualifiedName; + } + + private void setQualifiedName(String qualifiedName) { + getProperties().myQualifiedName = qualifiedName; + } + + private void setPackageName(String packageName) { + getProperties().myPackageName = packageName; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java deleted file mode 100644 index 40b75c4ffc71..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.ui.breakpoints; - -import com.intellij.debugger.DebuggerBundle; -import com.intellij.debugger.DebuggerManagerEx; -import com.intellij.debugger.HelpID; -import com.intellij.debugger.engine.JVMNameUtil; -import com.intellij.icons.AllIcons; -import com.intellij.ide.util.TreeClassChooser; -import com.intellij.ide.util.TreeClassChooserFactory; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiClassOwner; -import com.intellij.psi.search.GlobalSearchScope; -import org.jdom.Element; - -import javax.swing.*; - -/** - * @author Eugene Zhuravlev - * Date: Apr 26, 2005 - */ -public class ExceptionBreakpointFactory extends BreakpointFactory { - public Breakpoint createBreakpoint(Project project, final Element element) { - return new ExceptionBreakpoint(project); - } - - public Icon getIcon() { - return AllIcons.Debugger.Db_exception_breakpoint; - } - - public Icon getDisabledIcon() { - return AllIcons.Debugger.Db_disabled_exception_breakpoint; - } - - @Override - protected String getHelpID() { - return HelpID.EXCEPTION_BREAKPOINTS; - } - - @Override - public String getDisplayName() { - return DebuggerBundle.message("exception.breakpoints.tab.title"); - } - - @Override - public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) { - return new ExceptionBreakpointPropertiesPanel(project, compact); - } - - public Key<ExceptionBreakpoint> getBreakpointCategory() { - return ExceptionBreakpoint.CATEGORY; - } - - @Override - public boolean canAddBreakpoints() { - return true; - } - - @Override - public Breakpoint addBreakpoint(Project project) { - ExceptionBreakpoint breakpoint = null; - final PsiClass throwableClass = - JavaPsiFacade.getInstance(project).findClass("java.lang.Throwable", GlobalSearchScope.allScope(project)); - TreeClassChooser chooser = TreeClassChooserFactory.getInstance(project) - .createInheritanceClassChooser(DebuggerBundle.message("add.exception.breakpoint.classchooser.title"), - GlobalSearchScope.allScope(project), throwableClass, true, true, null); - chooser.showDialog(); - PsiClass selectedClass = chooser.getSelected(); - String qName = selectedClass == null ? null : JVMNameUtil.getNonAnonymousClassName(selectedClass); - - if (qName != null && qName.length() > 0) { - breakpoint = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager() - .addExceptionBreakpoint(qName, ((PsiClassOwner)selectedClass.getContainingFile()).getPackageName()); - } - return breakpoint; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointPropertiesPanel.java index 6d02499f227c..4af7275d1258 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointPropertiesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointPropertiesPanel.java @@ -21,31 +21,34 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.debugger.DebuggerBundle; -import com.intellij.ide.util.ClassFilter; -import com.intellij.openapi.project.Project; import com.intellij.ui.IdeBorderFactory; import com.intellij.util.ui.DialogUtil; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.java.debugger.breakpoints.properties.JavaExceptionBreakpointProperties; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -public class ExceptionBreakpointPropertiesPanel extends BreakpointPropertiesPanel { +public class ExceptionBreakpointPropertiesPanel extends XBreakpointCustomPropertiesPanel<XBreakpoint<JavaExceptionBreakpointProperties>> { private JCheckBox myNotifyCaughtCheckBox; private JCheckBox myNotifyUncaughtCheckBox; - private ExceptionBreakpoint myExceptionBreakpoint; + //private ExceptionBreakpoint myExceptionBreakpoint; - public ExceptionBreakpointPropertiesPanel(Project project, boolean compact) { - super(project, ExceptionBreakpoint.CATEGORY, compact); - } - - protected ClassFilter createClassConditionFilter() { - return null; - } + //public ExceptionBreakpointPropertiesPanel(Project project, boolean compact) { + // super(project, ExceptionBreakpoint.CATEGORY, compact); + //} - protected JComponent createSpecialBox() { + //protected ClassFilter createClassConditionFilter() { + // return null; + //} + @NotNull + @Override + public JComponent getComponent() { myNotifyCaughtCheckBox = new JCheckBox(DebuggerBundle.message("label.exception.breakpoint.properties.panel.caught.exception")); myNotifyUncaughtCheckBox = new JCheckBox(DebuggerBundle.message("label.exception.breakpoint.properties.panel.uncaught.exception")); DialogUtil.registerMnemonic(myNotifyCaughtCheckBox); @@ -91,25 +94,20 @@ public class ExceptionBreakpointPropertiesPanel extends BreakpointPropertiesPane return _panel; } - protected void updateCheckboxes() { - super.updateCheckboxes(); - myPassCountCheckbox.setEnabled(!(myExceptionBreakpoint instanceof AnyExceptionBreakpoint)); - } - - public void initFrom(Breakpoint breakpoint, boolean moreOptionsVisible) { - ExceptionBreakpoint exceptionBreakpoint = (ExceptionBreakpoint)breakpoint; - myExceptionBreakpoint = exceptionBreakpoint; - super.initFrom(breakpoint, moreOptionsVisible); + //protected void updateCheckboxes() { + // super.updateCheckboxes(); + // myPassCountCheckbox.setEnabled(!(myExceptionBreakpoint instanceof AnyExceptionBreakpoint)); + //} - myNotifyCaughtCheckBox.setSelected(exceptionBreakpoint.NOTIFY_CAUGHT); - myNotifyUncaughtCheckBox.setSelected(exceptionBreakpoint.NOTIFY_UNCAUGHT); + @Override + public void loadFrom(@NotNull XBreakpoint<JavaExceptionBreakpointProperties> breakpoint) { + myNotifyCaughtCheckBox.setSelected(breakpoint.getProperties().NOTIFY_CAUGHT); + myNotifyUncaughtCheckBox.setSelected(breakpoint.getProperties().NOTIFY_UNCAUGHT); } - public void saveTo(Breakpoint breakpoint) { - ExceptionBreakpoint exceptionBreakpoint = (ExceptionBreakpoint)breakpoint; - exceptionBreakpoint.NOTIFY_CAUGHT = myNotifyCaughtCheckBox.isSelected(); - exceptionBreakpoint.NOTIFY_UNCAUGHT = myNotifyUncaughtCheckBox.isSelected(); - - super.saveTo(breakpoint); + @Override + public void saveTo(@NotNull XBreakpoint<JavaExceptionBreakpointProperties> breakpoint) { + breakpoint.getProperties().NOTIFY_CAUGHT = myNotifyCaughtCheckBox.isSelected(); + breakpoint.getProperties().NOTIFY_UNCAUGHT = myNotifyUncaughtCheckBox.isSelected(); } }
\ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpoint.java index 365ae242b36d..aa3a29511a2f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpoint.java @@ -33,19 +33,17 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Processor; import com.intellij.util.text.CharArrayUtil; import com.intellij.xdebugger.XDebuggerUtil; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.sun.jdi.*; import com.sun.jdi.event.AccessWatchpointEvent; import com.sun.jdi.event.LocatableEvent; @@ -55,26 +53,23 @@ import com.sun.jdi.request.ModificationWatchpointRequest; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.java.debugger.breakpoints.properties.JavaFieldBreakpointProperties; import javax.swing.*; -import java.util.List; -public class FieldBreakpoint extends BreakpointWithHighlighter { +public class FieldBreakpoint extends BreakpointWithHighlighter<JavaFieldBreakpointProperties> { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.FieldBreakpoint"); - public boolean WATCH_MODIFICATION = true; - public boolean WATCH_ACCESS = false; private boolean myIsStatic; - private String myFieldName; @NonNls public static final Key<FieldBreakpoint> CATEGORY = BreakpointCategory.lookup("field_breakpoints"); - protected FieldBreakpoint(Project project) { - super(project); + protected FieldBreakpoint(Project project, XBreakpoint breakpoint) { + super(project, breakpoint); } - private FieldBreakpoint(Project project, RangeHighlighter highlighter, @NotNull String fieldName) { - super(project, highlighter); - myFieldName = fieldName; + private FieldBreakpoint(Project project, @NotNull String fieldName, XBreakpoint breakpoint) { + super(project, breakpoint); + setFieldName(fieldName); } public boolean isStatic() { @@ -82,10 +77,9 @@ public class FieldBreakpoint extends BreakpointWithHighlighter { } public String getFieldName() { - return myFieldName; + return getProperties().myFieldName; } - @Override protected Icon getDisabledIcon(boolean isMuted) { final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this); @@ -128,7 +122,7 @@ public class FieldBreakpoint extends BreakpointWithHighlighter { @Override public PsiField compute() { final PsiClass psiClass = getPsiClassAt(sourcePosition); - return psiClass != null ? psiClass.findFieldByName(myFieldName, true) : null; + return psiClass != null ? psiClass.findFieldByName(getFieldName(), true) : null; } }); if (field != null) { @@ -142,11 +136,15 @@ public class FieldBreakpoint extends BreakpointWithHighlighter { super.reload(psiFile); PsiField field = PositionUtil.getPsiElementAt(getProject(), PsiField.class, getSourcePosition()); if(field != null) { - myFieldName = field.getName(); + setFieldName(field.getName()); + PsiClass psiClass = field.getContainingClass(); + if (psiClass != null) { + getProperties().myClassName = psiClass.getQualifiedName(); + } myIsStatic = field.hasModifierProperty(PsiModifier.STATIC); } if (myIsStatic) { - INSTANCE_FILTERS_ENABLED = false; + setInstanceFiltersEnabled(false); } } @@ -181,20 +179,21 @@ public class FieldBreakpoint extends BreakpointWithHighlighter { ReferenceType refType) { VirtualMachineProxy vm = debugProcess.getVirtualMachineProxy(); try { - Field field = refType.fieldByName(myFieldName); + Field field = refType.fieldByName(getFieldName()); if (field == null) { - debugProcess.getRequestsManager().setInvalid(this, DebuggerBundle.message("error.invalid.breakpoint.missing.field.in.class", myFieldName, refType.name())); + debugProcess.getRequestsManager().setInvalid(this, DebuggerBundle.message("error.invalid.breakpoint.missing.field.in.class", + getFieldName(), refType.name())); return; } RequestManagerImpl manager = debugProcess.getRequestsManager(); - if (WATCH_MODIFICATION && vm.canWatchFieldModification()) { + if (isWatchModification() && vm.canWatchFieldModification()) { ModificationWatchpointRequest request = manager.createModificationWatchpointRequest(this, field); debugProcess.getRequestsManager().enableRequest(request); if (LOG.isDebugEnabled()) { LOG.debug("Modification request added"); } } - if (WATCH_ACCESS && vm.canWatchFieldAccess()) { + if (isWatchAccess() && vm.canWatchFieldAccess()) { AccessWatchpointRequest request = manager.createAccessWatchpointRequest(this, field); debugProcess.getRequestsManager().enableRequest(request); if (LOG.isDebugEnabled()) { @@ -284,11 +283,11 @@ public class FieldBreakpoint extends BreakpointWithHighlighter { return DebuggerBundle.message("status.breakpoint.invalid"); } final String className = getClassName(); - return className != null && !className.isEmpty() ? className + "." + myFieldName : myFieldName; + return className != null && !className.isEmpty() ? className + "." + getFieldName() : getFieldName(); } - public static FieldBreakpoint create(@NotNull Project project, @NotNull Document document, int lineIndex, String fieldName) { - FieldBreakpoint breakpoint = new FieldBreakpoint(project, createHighlighter(project, document, lineIndex), fieldName); + public static FieldBreakpoint create(@NotNull Project project, String fieldName, XBreakpoint xBreakpoint) { + FieldBreakpoint breakpoint = new FieldBreakpoint(project, fieldName, xBreakpoint); return (FieldBreakpoint)breakpoint.init(); } @@ -308,39 +307,39 @@ public class FieldBreakpoint extends BreakpointWithHighlighter { return field == getPsiField(); } - protected static FieldBreakpoint create(@NotNull Project project, @NotNull Field field, ObjectReference object) { - String fieldName = field.name(); - int line = 0; - Document document = null; - try { - List locations = field.declaringType().allLineLocations(); - if(!locations.isEmpty()) { - Location location = (Location)locations.get(0); - line = location.lineNumber(); - VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(location.sourcePath()); - if(file != null) { - PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - if(psiFile != null) { - document = PsiDocumentManager.getInstance(project).getDocument(psiFile); - } - } - } - } - catch (AbsentInformationException e) { - LOG.debug(e); - } - catch (InternalError e) { - LOG.debug(e); - } - - if(document == null) return null; - - FieldBreakpoint fieldBreakpoint = new FieldBreakpoint(project, createHighlighter(project, document, line), fieldName); - if (!fieldBreakpoint.isStatic()) { - fieldBreakpoint.addInstanceFilter(object.uniqueID()); - } - return (FieldBreakpoint)fieldBreakpoint.init(); - } + //protected static FieldBreakpoint create(@NotNull Project project, @NotNull Field field, ObjectReference object, XBreakpoint xBreakpoint) { + // String fieldName = field.name(); + // int line = 0; + // Document document = null; + // try { + // List locations = field.declaringType().allLineLocations(); + // if(!locations.isEmpty()) { + // Location location = (Location)locations.get(0); + // line = location.lineNumber(); + // VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(location.sourcePath()); + // if(file != null) { + // PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + // if(psiFile != null) { + // document = PsiDocumentManager.getInstance(project).getDocument(psiFile); + // } + // } + // } + // } + // catch (AbsentInformationException e) { + // LOG.debug(e); + // } + // catch (InternalError e) { + // LOG.debug(e); + // } + // + // if(document == null) return null; + // + // FieldBreakpoint fieldBreakpoint = new FieldBreakpoint(project, createHighlighter(project, document, line), fieldName, xBreakpoint); + // if (!fieldBreakpoint.isStatic()) { + // fieldBreakpoint.addInstanceFilter(object.uniqueID()); + // } + // return (FieldBreakpoint)fieldBreakpoint.init(); + //} public static PsiField findField(Project project, Document document, int offset) { PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); @@ -373,21 +372,41 @@ public class FieldBreakpoint extends BreakpointWithHighlighter { public void readExternal(@NotNull Element breakpointNode) throws InvalidDataException { super.readExternal(breakpointNode); //noinspection HardCodedStringLiteral - myFieldName = breakpointNode.getAttributeValue("field_name"); - if(myFieldName == null) { + setFieldName(breakpointNode.getAttributeValue("field_name")); + if(getFieldName() == null) { throw new InvalidDataException("No field name for field breakpoint"); } + try { + getProperties().WATCH_MODIFICATION = Boolean.valueOf(JDOMExternalizerUtil.readField(breakpointNode, "WATCH_MODIFICATION")); + } catch (Exception e) { + } + try { + getProperties().WATCH_ACCESS = Boolean.valueOf(JDOMExternalizerUtil.readField(breakpointNode, "WATCH_ACCESS")); + } catch (Exception e) { + } } - - @Override - @SuppressWarnings({"HardCodedStringLiteral"}) - public void writeExternal(@NotNull Element parentNode) throws WriteExternalException { - super.writeExternal(parentNode); - parentNode.setAttribute("field_name", getFieldName()); - } + // + //@Override + //@SuppressWarnings({"HardCodedStringLiteral"}) + //public void writeExternal(@NotNull Element parentNode) throws WriteExternalException { + // super.writeExternal(parentNode); + // parentNode.setAttribute("field_name", getFieldName()); + //} @Override public PsiElement getEvaluationElement() { return getPsiClass(); } + + private boolean isWatchModification() { + return getProperties().WATCH_MODIFICATION; + } + + private boolean isWatchAccess() { + return getProperties().WATCH_ACCESS; + } + + private void setFieldName(String fieldName) { + getProperties().myFieldName = fieldName; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java deleted file mode 100644 index 1bdef0c862e7..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.ui.breakpoints; - -import com.intellij.CommonBundle; -import com.intellij.debugger.DebuggerBundle; -import com.intellij.debugger.DebuggerManagerEx; -import com.intellij.debugger.HelpID; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Ref; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import org.jdom.Element; - -import javax.swing.*; - -/** - * @author Eugene Zhuravlev - * Date: Apr 26, 2005 - */ -public class FieldBreakpointFactory extends BreakpointFactory{ - public Breakpoint createBreakpoint(Project project, final Element element) { - return new FieldBreakpoint(project); - } - - public Icon getIcon() { - return AllIcons.Debugger.Db_field_breakpoint; - } - - public Icon getDisabledIcon() { - return AllIcons.Debugger.Db_disabled_field_breakpoint; - } - - @Override - protected String getHelpID() { - return HelpID.FIELD_WATCHPOINTS; - } - - @Override - public String getDisplayName() { - return DebuggerBundle.message("field.watchpoints.tab.title"); - } - - @Override - public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) { - return new FieldBreakpointPropertiesPanel(project, compact); - } - - public Key<FieldBreakpoint> getBreakpointCategory() { - return FieldBreakpoint.CATEGORY; - } - - @Override - public Breakpoint addBreakpoint(final Project project) { - final Ref<Breakpoint> result = Ref.create(null); - AddFieldBreakpointDialog dialog = new AddFieldBreakpointDialog(project) { - protected boolean validateData() { - String className = getClassName(); - if (className.length() == 0) { - Messages.showMessageDialog(project, DebuggerBundle.message("error.field.breakpoint.class.name.not.specified"), - DebuggerBundle.message("add.field.breakpoint.dialog.title"), Messages.getErrorIcon()); - return false; - } - String fieldName = getFieldName(); - if (fieldName.length() == 0) { - Messages.showMessageDialog(project, DebuggerBundle.message("error.field.breakpoint.field.name.not.specified"), - DebuggerBundle.message("add.field.breakpoint.dialog.title"), Messages.getErrorIcon()); - return false; - } - PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)); - if (psiClass != null) { - PsiFile psiFile = psiClass.getContainingFile(); - Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); - if(document != null) { - PsiField field = psiClass.findFieldByName(fieldName, true); - if(field != null) { - int line = document.getLineNumber(field.getTextOffset()); - FieldBreakpoint fieldBreakpoint = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().addFieldBreakpoint(document, line, fieldName); - if (fieldBreakpoint != null) { - result.set(fieldBreakpoint); - return true; - } - } - else { - Messages.showMessageDialog(project, - DebuggerBundle.message("error.field.breakpoint.field.not.found", className, fieldName, fieldName), - CommonBundle.getErrorTitle(), - Messages.getErrorIcon() - ); - } - } - } else { - Messages.showMessageDialog(project, - DebuggerBundle.message("error.field.breakpoint.class.sources.not.found", className, fieldName, className), - CommonBundle.getErrorTitle(), - Messages.getErrorIcon() - ); - } - return false; - } - }; - dialog.show(); - return result.get(); - } - - @Override - public boolean canAddBreakpoints() { - return true; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointPropertiesPanel.java index bec12645dd80..4d0bec2e165b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointPropertiesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointPropertiesPanel.java @@ -21,24 +21,30 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.debugger.DebuggerBundle; -import com.intellij.openapi.project.Project; import com.intellij.ui.IdeBorderFactory; import com.intellij.util.ui.DialogUtil; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.java.debugger.breakpoints.properties.JavaFieldBreakpointProperties; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -public class FieldBreakpointPropertiesPanel extends BreakpointPropertiesPanel { +public class FieldBreakpointPropertiesPanel extends XBreakpointCustomPropertiesPanel<XLineBreakpoint<JavaFieldBreakpointProperties>> { private JCheckBox myWatchAccessCheckBox; private JCheckBox myWatchModificationCheckBox; - public FieldBreakpointPropertiesPanel(final Project project, boolean compact) { - super(project, FieldBreakpoint.CATEGORY, compact); - } + //public FieldBreakpointPropertiesPanel(final Project project, boolean compact) { + // super(project, FieldBreakpoint.CATEGORY, compact); + //} + - protected JComponent createSpecialBox() { + @NotNull + @Override + public JComponent getComponent() { JPanel _panel; JPanel _panel0; myWatchAccessCheckBox = new JCheckBox(DebuggerBundle.message("label.filed.breakpoint.properties.panel.field.access")); @@ -86,20 +92,15 @@ public class FieldBreakpointPropertiesPanel extends BreakpointPropertiesPanel { return _panel; } - public void initFrom(Breakpoint breakpoint, boolean moreOptionsVisible) { - super.initFrom(breakpoint, moreOptionsVisible); - FieldBreakpoint fieldBreakpoint = (FieldBreakpoint)breakpoint; - - myWatchAccessCheckBox.setSelected(fieldBreakpoint.WATCH_ACCESS); - myWatchModificationCheckBox.setSelected(fieldBreakpoint.WATCH_MODIFICATION); + @Override + public void loadFrom(@NotNull XLineBreakpoint<JavaFieldBreakpointProperties> breakpoint) { + myWatchAccessCheckBox.setSelected(breakpoint.getProperties().WATCH_ACCESS); + myWatchModificationCheckBox.setSelected(breakpoint.getProperties().WATCH_MODIFICATION); } - public void saveTo(Breakpoint breakpoint) { - FieldBreakpoint fieldBreakpoint = (FieldBreakpoint)breakpoint; - - fieldBreakpoint.WATCH_ACCESS = myWatchAccessCheckBox.isSelected(); - fieldBreakpoint.WATCH_MODIFICATION = myWatchModificationCheckBox.isSelected(); - - super.saveTo(breakpoint); + @Override + public void saveTo(@NotNull XLineBreakpoint<JavaFieldBreakpointProperties> breakpoint) { + breakpoint.getProperties().WATCH_ACCESS = myWatchAccessCheckBox.isSelected(); + breakpoint.getProperties().WATCH_MODIFICATION = myWatchModificationCheckBox.isSelected(); } }
\ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java index 8aa57bd351d8..6a628f189bc5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.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. @@ -13,250 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * class FilteredRequestor - * @author Jeka - */ package com.intellij.debugger.ui.breakpoints; -import com.intellij.debugger.*; -import com.intellij.debugger.engine.ContextUtil; -import com.intellij.debugger.engine.DebugProcessImpl; -import com.intellij.debugger.engine.evaluation.*; -import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl; -import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; +import com.intellij.debugger.InstanceFilter; import com.intellij.debugger.engine.requests.LocatableEventRequestor; -import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; -import com.intellij.psi.PsiElement; import com.intellij.ui.classFilter.ClassFilter; -import com.sun.jdi.BooleanValue; -import com.sun.jdi.ObjectReference; -import com.sun.jdi.VMDisconnectedException; -import com.sun.jdi.Value; -import com.sun.jdi.event.LocatableEvent; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -public abstract class FilteredRequestor implements LocatableEventRequestor, JDOMExternalizable { - - public String SUSPEND_POLICY = DebuggerSettings.SUSPEND_ALL; - public boolean SUSPEND = true; - - public boolean COUNT_FILTER_ENABLED = false; - public int COUNT_FILTER = 0; - - public boolean CONDITION_ENABLED = false; - private TextWithImports myCondition; - - public boolean CLASS_FILTERS_ENABLED = false; - private ClassFilter[] myClassFilters = ClassFilter.EMPTY_ARRAY; - private ClassFilter[] myClassExclusionFilters = ClassFilter.EMPTY_ARRAY; - - public boolean INSTANCE_FILTERS_ENABLED = false; - private InstanceFilter[] myInstanceFilters = InstanceFilter.EMPTY_ARRAY; - - @NonNls private static final String FILTER_OPTION_NAME = "filter"; - @NonNls private static final String EXCLUSION_FILTER_OPTION_NAME = "exclusion_filter"; - @NonNls private static final String INSTANCE_ID_OPTION_NAME = "instance_id"; - @NonNls private static final String CONDITION_OPTION_NAME = "CONDITION"; - protected final Project myProject; - - public FilteredRequestor(@NotNull Project project) { - myProject = project; - myCondition = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""); - } - - public InstanceFilter[] getInstanceFilters() { - return myInstanceFilters; - } - - public void setInstanceFilters(InstanceFilter[] instanceFilters) { - myInstanceFilters = instanceFilters != null? instanceFilters : InstanceFilter.EMPTY_ARRAY; - } - - public String getSuspendPolicy() { - return SUSPEND? SUSPEND_POLICY : DebuggerSettings.SUSPEND_NONE; - } - - /** - * @return true if the ID was added or false otherwise - */ - private boolean hasObjectID(long id) { - for (InstanceFilter instanceFilter : myInstanceFilters) { - if (instanceFilter.getId() == id) { - return true; - } - } - return false; - } - - protected void addInstanceFilter(long l) { - final InstanceFilter[] filters = new InstanceFilter[myInstanceFilters.length + 1]; - System.arraycopy(myInstanceFilters, 0, filters, 0, myInstanceFilters.length); - filters[myInstanceFilters.length] = InstanceFilter.create(String.valueOf(l)); - myInstanceFilters = filters; - } - public final ClassFilter[] getClassFilters() { - return myClassFilters; - } - - public final void setClassFilters(ClassFilter[] classFilters) { - myClassFilters = classFilters != null? classFilters : ClassFilter.EMPTY_ARRAY; - } - - public ClassFilter[] getClassExclusionFilters() { - return myClassExclusionFilters; - } - - public void setClassExclusionFilters(ClassFilter[] classExclusionFilters) { - myClassExclusionFilters = classExclusionFilters != null? classExclusionFilters : ClassFilter.EMPTY_ARRAY; - } - - public void readExternal(Element parentNode) throws InvalidDataException { - DefaultJDOMExternalizer.readExternal(this, parentNode); - if (DebuggerSettings.SUSPEND_NONE.equals(SUSPEND_POLICY)) { // compatibility with older format - SUSPEND = false; - SUSPEND_POLICY = DebuggerSettings.SUSPEND_ALL; - } - String condition = JDOMExternalizerUtil.readField(parentNode, CONDITION_OPTION_NAME); - if (condition != null) { - setCondition(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, condition)); - } - - myClassFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(FILTER_OPTION_NAME)); - myClassExclusionFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(EXCLUSION_FILTER_OPTION_NAME)); - - final ClassFilter [] instanceFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(INSTANCE_ID_OPTION_NAME)); - final List<InstanceFilter> iFilters = new ArrayList<InstanceFilter>(instanceFilters.length); - - for (ClassFilter instanceFilter : instanceFilters) { - try { - iFilters.add(InstanceFilter.create(instanceFilter)); - } - catch (Exception e) { - } - } - myInstanceFilters = iFilters.isEmpty() ? InstanceFilter.EMPTY_ARRAY : iFilters.toArray(new InstanceFilter[iFilters.size()]); - } - - public void writeExternal(Element parentNode) throws WriteExternalException { - DefaultJDOMExternalizer.writeExternal(this, parentNode); - JDOMExternalizerUtil.writeField(parentNode, CONDITION_OPTION_NAME, getCondition().toExternalForm()); - DebuggerUtilsEx.writeFilters(parentNode, FILTER_OPTION_NAME, myClassFilters); - DebuggerUtilsEx.writeFilters(parentNode, EXCLUSION_FILTER_OPTION_NAME, myClassExclusionFilters); - DebuggerUtilsEx.writeFilters(parentNode, INSTANCE_ID_OPTION_NAME, InstanceFilter.createClassFilters(myInstanceFilters)); - } - - public boolean evaluateCondition(final EvaluationContextImpl context, LocatableEvent event) throws EvaluateException { - if(COUNT_FILTER_ENABLED) { - final DebugProcessImpl debugProcess = context.getDebugProcess(); - debugProcess.getVirtualMachineProxy().suspend(); - debugProcess.getRequestsManager().deleteRequest(this); - ((Breakpoint)this).createRequest(debugProcess); - debugProcess.getVirtualMachineProxy().resume(); - } - if (INSTANCE_FILTERS_ENABLED) { - Value value = context.getThisObject(); - if (value != null) { // non-static - ObjectReference reference = (ObjectReference)value; - if(!hasObjectID(reference.uniqueID())) { - return false; - } - } - } - - if (CLASS_FILTERS_ENABLED) { - String typeName = calculateEventClass(context, event); - if (!typeMatchesClassFilters(typeName)) return false; - } - - if (CONDITION_ENABLED && getCondition() != null && !"".equals(getCondition().getText())) { - try { - ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(context.getProject(), new EvaluatingComputable<ExpressionEvaluator>() { - public ExpressionEvaluator compute() throws EvaluateException { - final SourcePosition contextSourcePosition = ContextUtil.getSourcePosition(context); - // IMPORTANT: calculate context psi element basing on the location where the exception - // has been hit, not on the location where it was set. (For line breakpoints these locations are the same, however, - // for method, exception and field breakpoints these locations differ) - PsiElement contextPsiElement = ContextUtil.getContextElement(contextSourcePosition); - if (contextPsiElement == null) { - contextPsiElement = getEvaluationElement(); // as a last resort - } - return EvaluatorBuilderImpl.build(getCondition(), contextPsiElement, contextSourcePosition); - } - }); - final Value value = evaluator.evaluate(context); - if (!(value instanceof BooleanValue)) { - throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected")); - } - if(!((BooleanValue)value).booleanValue()) { - return false; - } - } - catch (EvaluateException ex) { - if(ex.getCause() instanceof VMDisconnectedException) { - return false; - } - throw EvaluateExceptionUtil.createEvaluateException( - DebuggerBundle.message("error.failed.evaluating.breakpoint.condition", getCondition(), ex.getMessage()) - ); - } - return true; - } - - return true; - } - - protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException { - return event.location().declaringType().name(); - } - - private boolean typeMatchesClassFilters(@Nullable String typeName) { - if (typeName == null) { - return true; - } - boolean matches = false, hasEnabled = false; - for (ClassFilter classFilter : getClassFilters()) { - if (classFilter.isEnabled()) { - hasEnabled = true; - if (classFilter.matches(typeName)) { - matches = true; - break; - } - } - } - if(hasEnabled && !matches) { - return false; - } - for (ClassFilter classFilter : getClassExclusionFilters()) { - if (classFilter.isEnabled() && classFilter.matches(typeName)) { - return false; - } - } - return true; - } - - public abstract PsiElement getEvaluationElement(); +/** + * @author egor + */ +public interface FilteredRequestor extends LocatableEventRequestor { + String getSuspendPolicy(); - public TextWithImports getCondition() { - return myCondition; - } + boolean isInstanceFiltersEnabled(); + InstanceFilter[] getInstanceFilters(); - public void setCondition(TextWithImports condition) { - myCondition = condition; - } + boolean isCountFilterEnabled(); + int getCountFilter(); - public Project getProject() { - return myProject; - } + boolean isClassFiltersEnabled(); + ClassFilter[] getClassFilters(); + ClassFilter[] getClassExclusionFilters(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestorImpl.java new file mode 100644 index 000000000000..496292881354 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestorImpl.java @@ -0,0 +1,243 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * class FilteredRequestorImpl + * @author Jeka + */ +package com.intellij.debugger.ui.breakpoints; + +import com.intellij.debugger.InstanceFilter; +import com.intellij.debugger.engine.evaluation.*; +import com.intellij.debugger.engine.events.SuspendContextCommandImpl; +import com.intellij.debugger.impl.DebuggerUtilsEx; +import com.intellij.debugger.settings.DebuggerSettings; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.*; +import com.intellij.psi.PsiElement; +import com.intellij.ui.classFilter.ClassFilter; +import com.sun.jdi.event.LocatableEvent; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/* + * Not used any more, since move to xBreakpoints + */ +public class FilteredRequestorImpl implements JDOMExternalizable, FilteredRequestor { + + public String SUSPEND_POLICY = DebuggerSettings.SUSPEND_ALL; + public boolean SUSPEND = true; + + public boolean COUNT_FILTER_ENABLED = false; + public int COUNT_FILTER = 0; + + public boolean CONDITION_ENABLED = false; + private TextWithImports myCondition; + + public boolean CLASS_FILTERS_ENABLED = false; + private ClassFilter[] myClassFilters = ClassFilter.EMPTY_ARRAY; + private ClassFilter[] myClassExclusionFilters = ClassFilter.EMPTY_ARRAY; + + public boolean INSTANCE_FILTERS_ENABLED = false; + private InstanceFilter[] myInstanceFilters = InstanceFilter.EMPTY_ARRAY; + + @NonNls private static final String FILTER_OPTION_NAME = "filter"; + @NonNls private static final String EXCLUSION_FILTER_OPTION_NAME = "exclusion_filter"; + @NonNls private static final String INSTANCE_ID_OPTION_NAME = "instance_id"; + @NonNls private static final String CONDITION_OPTION_NAME = "CONDITION"; + protected final Project myProject; + + public FilteredRequestorImpl(@NotNull Project project) { + myProject = project; + myCondition = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""); + } + + public InstanceFilter[] getInstanceFilters() { + return myInstanceFilters; + } + + public void setInstanceFilters(InstanceFilter[] instanceFilters) { + myInstanceFilters = instanceFilters != null? instanceFilters : InstanceFilter.EMPTY_ARRAY; + } + + public String getSuspendPolicy() { + return SUSPEND? SUSPEND_POLICY : DebuggerSettings.SUSPEND_NONE; + } + + /** + * @return true if the ID was added or false otherwise + */ + private boolean hasObjectID(long id) { + for (InstanceFilter instanceFilter : myInstanceFilters) { + if (instanceFilter.getId() == id) { + return true; + } + } + return false; + } + + protected void addInstanceFilter(long l) { + final InstanceFilter[] filters = new InstanceFilter[myInstanceFilters.length + 1]; + System.arraycopy(myInstanceFilters, 0, filters, 0, myInstanceFilters.length); + filters[myInstanceFilters.length] = InstanceFilter.create(String.valueOf(l)); + myInstanceFilters = filters; + } + + public final ClassFilter[] getClassFilters() { + return myClassFilters; + } + + public final void setClassFilters(ClassFilter[] classFilters) { + myClassFilters = classFilters != null? classFilters : ClassFilter.EMPTY_ARRAY; + } + + public ClassFilter[] getClassExclusionFilters() { + return myClassExclusionFilters; + } + + public void setClassExclusionFilters(ClassFilter[] classExclusionFilters) { + myClassExclusionFilters = classExclusionFilters != null? classExclusionFilters : ClassFilter.EMPTY_ARRAY; + } + + public void readTo(Element parentNode, Breakpoint breakpoint) throws InvalidDataException { + readExternal(parentNode); + if (SUSPEND) { + breakpoint.setSuspendPolicy(SUSPEND_POLICY); + } + else { + breakpoint.setSuspendPolicy(DebuggerSettings.SUSPEND_NONE); + } + + breakpoint.setCountFilterEnabled(COUNT_FILTER_ENABLED); + breakpoint.setCountFilter(COUNT_FILTER); + + breakpoint.setCondition(CONDITION_ENABLED ? myCondition : null); + + breakpoint.setClassFiltersEnabled(CLASS_FILTERS_ENABLED); + breakpoint.setClassFilters(getClassFilters()); + breakpoint.setClassExclusionFilters(getClassExclusionFilters()); + + breakpoint.setInstanceFiltersEnabled(INSTANCE_FILTERS_ENABLED); + breakpoint.setInstanceFilters(getInstanceFilters()); + } + + public void readExternal(Element parentNode) throws InvalidDataException { + DefaultJDOMExternalizer.readExternal(this, parentNode); + if (DebuggerSettings.SUSPEND_NONE.equals(SUSPEND_POLICY)) { // compatibility with older format + SUSPEND = false; + SUSPEND_POLICY = DebuggerSettings.SUSPEND_ALL; + } + String condition = JDOMExternalizerUtil.readField(parentNode, CONDITION_OPTION_NAME); + if (condition != null) { + setCondition(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, condition)); + } + + myClassFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(FILTER_OPTION_NAME)); + myClassExclusionFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(EXCLUSION_FILTER_OPTION_NAME)); + + final ClassFilter [] instanceFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(INSTANCE_ID_OPTION_NAME)); + final List<InstanceFilter> iFilters = new ArrayList<InstanceFilter>(instanceFilters.length); + + for (ClassFilter instanceFilter : instanceFilters) { + try { + iFilters.add(InstanceFilter.create(instanceFilter)); + } + catch (Exception e) { + } + } + myInstanceFilters = iFilters.isEmpty() ? InstanceFilter.EMPTY_ARRAY : iFilters.toArray(new InstanceFilter[iFilters.size()]); + } + + public void writeExternal(Element parentNode) throws WriteExternalException { + DefaultJDOMExternalizer.writeExternal(this, parentNode); + JDOMExternalizerUtil.writeField(parentNode, CONDITION_OPTION_NAME, getCondition().toExternalForm()); + DebuggerUtilsEx.writeFilters(parentNode, FILTER_OPTION_NAME, myClassFilters); + DebuggerUtilsEx.writeFilters(parentNode, EXCLUSION_FILTER_OPTION_NAME, myClassExclusionFilters); + DebuggerUtilsEx.writeFilters(parentNode, INSTANCE_ID_OPTION_NAME, InstanceFilter.createClassFilters(myInstanceFilters)); + } + + protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException { + return event.location().declaringType().name(); + } + + private boolean typeMatchesClassFilters(@Nullable String typeName) { + if (typeName == null) { + return true; + } + boolean matches = false, hasEnabled = false; + for (ClassFilter classFilter : getClassFilters()) { + if (classFilter.isEnabled()) { + hasEnabled = true; + if (classFilter.matches(typeName)) { + matches = true; + break; + } + } + } + if(hasEnabled && !matches) { + return false; + } + for (ClassFilter classFilter : getClassExclusionFilters()) { + if (classFilter.isEnabled() && classFilter.matches(typeName)) { + return false; + } + } + return true; + } + + public PsiElement getEvaluationElement() { + return null; + } + + public TextWithImports getCondition() { + return myCondition; + } + + public void setCondition(TextWithImports condition) { + myCondition = condition; + } + + public Project getProject() { + return myProject; + } + + public boolean isCountFilterEnabled() { + return COUNT_FILTER_ENABLED; + } + + public int getCountFilter() { + return COUNT_FILTER; + } + + public boolean isClassFiltersEnabled() { + return CLASS_FILTERS_ENABLED; + } + + public boolean isInstanceFiltersEnabled() { + return INSTANCE_FILTERS_ENABLED; + } + + @Override + public boolean processLocatableEvent(SuspendContextCommandImpl action, LocatableEvent event) + throws EventProcessingException { + return false; + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java deleted file mode 100644 index ec3577cbae0a..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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.debugger.ui.breakpoints; - -import com.intellij.debugger.DebuggerManagerEx; -import com.intellij.debugger.SourcePosition; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.SimpleColoredComponent; -import com.intellij.ui.SimpleTextAttributes; -import com.intellij.ui.popup.util.DetailView; -import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -class JavaBreakpointItem extends BreakpointItem { - private final Breakpoint myBreakpoint; - private BreakpointFactory myBreakpointFactory; - private BreakpointPropertiesPanel myBreakpointPropertiesPanel; - - public JavaBreakpointItem(@Nullable BreakpointFactory breakpointFactory, Breakpoint breakpoint) { - myBreakpointFactory = breakpointFactory; - myBreakpoint = breakpoint; - } - - @Override - public void setupGenericRenderer(SimpleColoredComponent renderer, boolean plainView) { - if (plainView) { - renderer.setIcon(myBreakpoint.getIcon()); - } - renderer.append(plainView ? StringUtil.shortenTextWithEllipsis(myBreakpoint.getShortName(), 60, 0) : myBreakpoint.getDisplayName(), - isEnabled() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES); - } - - @Override - public Icon getIcon() { - return myBreakpoint.getIcon(); - } - - @Override - public String getDisplayText() { - return myBreakpoint.getDisplayName(); - } - - @Override - public String speedSearchText() { - return myBreakpoint.getDisplayName(); - } - - @Override - public String footerText() { - return myBreakpoint.getDisplayName(); - } - - @Override - protected void doUpdateDetailView(DetailView panel, boolean editorOnly) { - //saveState(); - if (myBreakpointPropertiesPanel != null) { - myBreakpointPropertiesPanel.dispose(); - myBreakpointPropertiesPanel = null; - } - - if (!editorOnly) { - myBreakpointPropertiesPanel = myBreakpointFactory != null ? myBreakpointFactory - .createBreakpointPropertiesPanel(myBreakpoint.getProject(), false) : null; - - if (myBreakpointPropertiesPanel != null) { - myBreakpointPropertiesPanel.initFrom(myBreakpoint, true); - - final JPanel mainPanel = myBreakpointPropertiesPanel.getPanel(); - panel.setPropertiesPanel(mainPanel); - } - else { - panel.setPropertiesPanel(null); - } - } - - if (myBreakpoint instanceof BreakpointWithHighlighter) { - SourcePosition sourcePosition = ((BreakpointWithHighlighter)myBreakpoint).getSourcePosition(); - VirtualFile virtualFile = sourcePosition.getFile().getVirtualFile(); - showInEditor(panel, virtualFile, sourcePosition.getLine()); - } else { - panel.clearEditor(); - } - if (myBreakpointPropertiesPanel != null) { - myBreakpointPropertiesPanel.setDetailView(panel); - } - } - - @Override - public void navigate(boolean requestFocus) { - if (myBreakpoint instanceof BreakpointWithHighlighter) { - ((BreakpointWithHighlighter)myBreakpoint).getSourcePosition().navigate(requestFocus); - } - } - - @Override - public boolean canNavigate() { - return myBreakpoint instanceof BreakpointWithHighlighter && ((BreakpointWithHighlighter)myBreakpoint).getSourcePosition().canNavigate(); - } - - @Override - public boolean canNavigateToSource() { - return myBreakpoint instanceof BreakpointWithHighlighter && - ((BreakpointWithHighlighter)myBreakpoint).getSourcePosition().canNavigateToSource(); - } - - @Override - public boolean allowedToRemove() { - return myBreakpointFactory != null && myBreakpointFactory.breakpointCanBeRemoved(myBreakpoint); - } - - @Override - public void removed(Project project) { - dispose(); - DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().removeBreakpoint(myBreakpoint); - } - - @Override - public void saveState() { - if (myBreakpointPropertiesPanel != null) { - myBreakpointPropertiesPanel.saveTo(myBreakpoint); - } - } - - @Override - public Object getBreakpoint() { - return myBreakpoint; - } - - @Override - public boolean isEnabled() { - return myBreakpoint.ENABLED; - } - - @Override - public void setEnabled(boolean state) { - myBreakpoint.ENABLED = state; - myBreakpoint.updateUI(); - DebuggerManagerEx.getInstanceEx(myBreakpoint.getProject()).getBreakpointManager().fireBreakpointChanged(myBreakpoint); - } - - @Override - public boolean isDefaultBreakpoint() { - return myBreakpoint.getCategory().equals(ExceptionBreakpoint.CATEGORY); - } - - @Override - protected void dispose() { - if (myBreakpointPropertiesPanel != null) { - myBreakpointPropertiesPanel.dispose(); - myBreakpointPropertiesPanel = null; - } - } - - @Override - public int compareTo(@NotNull BreakpointItem breakpointItem) { - final Object breakpoint = breakpointItem.getBreakpoint(); - if (breakpoint instanceof Breakpoint) { - return -getIndexOf(myBreakpoint) + getIndexOf((Breakpoint)breakpoint); - } - return getDisplayText().compareTo(breakpointItem.getDisplayText()); - } - - private int getIndexOf(Breakpoint breakpoint) { - return DebuggerManagerEx.getInstanceEx(myBreakpoint.getProject()).getBreakpointManager().getBreakpoints().indexOf(breakpoint); - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointType.java index 802657b44fd9..2776032a2f4f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointPropertiesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointType.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. @@ -13,17 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * Class LineBreakpointPropertiesPanel - * @author Jeka - */ package com.intellij.debugger.ui.breakpoints; import com.intellij.openapi.project.Project; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; -public class LineBreakpointPropertiesPanel extends BreakpointPropertiesPanel { - public LineBreakpointPropertiesPanel(Project project, boolean compact) { - super(project, LineBreakpoint.CATEGORY, compact); - } -}
\ No newline at end of file +/** + * Base class for all Java breakpoint types + * @author egor + */ +public interface JavaBreakpointType<P extends JavaBreakpointProperties> { + Breakpoint createJavaBreakpoint(Project project, XBreakpoint<P> breakpoint); +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointTypeBase.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointTypeBase.java new file mode 100644 index 000000000000..0bb20d620c2d --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointTypeBase.java @@ -0,0 +1,75 @@ +/* + * 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. + * 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.debugger.ui.breakpoints; + +import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.ui.JavaDebuggerSupport; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import com.intellij.xdebugger.XDebuggerUtil; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.XBreakpointType; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.JavaDebuggerEditorsProvider; +import org.jetbrains.java.debugger.breakpoints.JavaBreakpointFiltersPanel; +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; + +/** + * Base class for non-line java breakpoint + * @author egor + */ +public abstract class JavaBreakpointTypeBase<T extends JavaBreakpointProperties> extends XBreakpointType<XBreakpoint<T>, T> { + protected JavaBreakpointTypeBase(@NonNls @NotNull String id, @Nls @NotNull String title) { + super(id, title, true); + } + + @Override + public final boolean isAddBreakpointButtonVisible() { + return true; + } + + @Nullable + @Override + public final XBreakpointCustomPropertiesPanel<XBreakpoint<T>> createCustomRightPropertiesPanel(@NotNull Project project) { + return new JavaBreakpointFiltersPanel<T, XBreakpoint<T>>(project); + } + + @Nullable + @Override + public final XDebuggerEditorsProvider getEditorsProvider(@NotNull XBreakpoint<T> breakpoint, @NotNull Project project) { + return new JavaDebuggerEditorsProvider(); + } + + @Nullable + @Override + public XSourcePosition getSourcePosition(@NotNull XBreakpoint<T> breakpoint) { + BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(JavaDebuggerSupport.getCurrentProject()).getBreakpointManager(); + Breakpoint javaBreakpoint = breakpointManager.findBreakpoint(breakpoint); + if (javaBreakpoint != null) { + PsiClass aClass = javaBreakpoint.getPsiClass(); + if (aClass != null && aClass.getContainingFile() != null) { + return XDebuggerUtil.getInstance().createPositionByOffset(aClass.getContainingFile().getVirtualFile(), aClass.getTextOffset()); + } + } + return null; + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaExceptionBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaExceptionBreakpointType.java new file mode 100644 index 000000000000..d5d4b714875c --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaExceptionBreakpointType.java @@ -0,0 +1,138 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.ui.breakpoints; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.HelpID; +import com.intellij.debugger.engine.JVMNameUtil; +import com.intellij.icons.AllIcons; +import com.intellij.ide.util.TreeClassChooser; +import com.intellij.ide.util.TreeClassChooserFactory; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiClassOwner; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.xdebugger.XDebuggerManager; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaExceptionBreakpointProperties; + +import javax.swing.*; + +/** + * @author Eugene Zhuravlev + * Date: Apr 26, 2005 + */ +public class JavaExceptionBreakpointType extends JavaBreakpointTypeBase<JavaExceptionBreakpointProperties> + implements JavaBreakpointType<JavaExceptionBreakpointProperties> { + public JavaExceptionBreakpointType() { + super("java-exception", DebuggerBundle.message("exception.breakpoints.tab.title")); + } + + @NotNull + @Override + public Icon getEnabledIcon() { + return AllIcons.Debugger.Db_exception_breakpoint; + } + + @NotNull + @Override + public Icon getDisabledIcon() { + return AllIcons.Debugger.Db_disabled_exception_breakpoint; + } + + //@Override + protected String getHelpID() { + return HelpID.EXCEPTION_BREAKPOINTS; + } + + //@Override + public String getDisplayName() { + return DebuggerBundle.message("exception.breakpoints.tab.title"); + } + + @Override + public String getDisplayText(XBreakpoint<JavaExceptionBreakpointProperties> breakpoint) { + String name = breakpoint.getProperties().myQualifiedName; + if (name != null) { + return DebuggerBundle.message("breakpoint.exception.breakpoint.display.name", name); + } + else { + return DebuggerBundle.message("breakpoint.any.exception.display.name"); + } + } + + @Nullable + @Override + public JavaExceptionBreakpointProperties createProperties() { + return new JavaExceptionBreakpointProperties(); + } + + @Nullable + @Override + public XBreakpointCustomPropertiesPanel<XBreakpoint<JavaExceptionBreakpointProperties>> createCustomPropertiesPanel() { + return new ExceptionBreakpointPropertiesPanel(); + } + + @Nullable + @Override + public XBreakpoint<JavaExceptionBreakpointProperties> createDefaultBreakpoint(@NotNull XBreakpointCreator<JavaExceptionBreakpointProperties> creator) { + return creator.createBreakpoint(new JavaExceptionBreakpointProperties()); + } + + //public Key<ExceptionBreakpoint> getBreakpointCategory() { + // return ExceptionBreakpoint.CATEGORY; + //} + + @Nullable + @Override + public XBreakpoint<JavaExceptionBreakpointProperties> addBreakpoint(final Project project, JComponent parentComponent) { + final PsiClass throwableClass = + JavaPsiFacade.getInstance(project).findClass("java.lang.Throwable", GlobalSearchScope.allScope(project)); + TreeClassChooser chooser = TreeClassChooserFactory.getInstance(project) + .createInheritanceClassChooser(DebuggerBundle.message("add.exception.breakpoint.classchooser.title"), + GlobalSearchScope.allScope(project), throwableClass, true, true, null); + chooser.showDialog(); + final PsiClass selectedClass = chooser.getSelected(); + final String qName = selectedClass == null ? null : JVMNameUtil.getNonAnonymousClassName(selectedClass); + + if (qName != null && qName.length() > 0) { + return ApplicationManager.getApplication().runWriteAction(new Computable<XBreakpoint<JavaExceptionBreakpointProperties>>() { + @Override + public XBreakpoint<JavaExceptionBreakpointProperties> compute() { + return XDebuggerManager.getInstance(project).getBreakpointManager().addBreakpoint( + JavaExceptionBreakpointType.this, new JavaExceptionBreakpointProperties(qName, ((PsiClassOwner)selectedClass.getContainingFile()).getPackageName())); + } + }); + } + return null; + } + + @Override + public Breakpoint createJavaBreakpoint(Project project, XBreakpoint<JavaExceptionBreakpointProperties> breakpoint) { + if (!XDebuggerManager.getInstance(project).getBreakpointManager().isDefaultBreakpoint(breakpoint)) { + return new ExceptionBreakpoint(project, breakpoint); + } + else { + return new AnyExceptionBreakpoint(project, breakpoint); + } + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaFieldBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaFieldBreakpointType.java new file mode 100644 index 000000000000..74a6f2df61cc --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaFieldBreakpointType.java @@ -0,0 +1,166 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.ui.breakpoints; + +import com.intellij.CommonBundle; +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.HelpID; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.xdebugger.XDebuggerManager; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaFieldBreakpointProperties; + +import javax.swing.*; + +/** + * @author Eugene Zhuravlev + * Date: Apr 26, 2005 + */ +public class JavaFieldBreakpointType extends JavaLineBreakpointTypeBase<JavaFieldBreakpointProperties> implements JavaBreakpointType { + public JavaFieldBreakpointType() { + super("java-field", DebuggerBundle.message("field.watchpoints.tab.title")); + } + + @NotNull + @Override + public Icon getEnabledIcon() { + return AllIcons.Debugger.Db_field_breakpoint; + } + + @NotNull + @Override + public Icon getDisabledIcon() { + return AllIcons.Debugger.Db_disabled_field_breakpoint; + } + + //@Override + protected String getHelpID() { + return HelpID.FIELD_WATCHPOINTS; + } + + //@Override + public String getDisplayName() { + return DebuggerBundle.message("field.watchpoints.tab.title"); + } + + @Override + public String getShortText(XLineBreakpoint<JavaFieldBreakpointProperties> breakpoint) { + return getText(breakpoint); + } + + public String getText(XLineBreakpoint<JavaFieldBreakpointProperties> breakpoint) { + //if(!isValid()) { + // return DebuggerBundle.message("status.breakpoint.invalid"); + //} + + JavaFieldBreakpointProperties properties = breakpoint.getProperties(); + final String className = properties.myClassName; + return className != null && !className.isEmpty() ? className + "." + properties.myFieldName : properties.myFieldName; + } + + @Nullable + @Override + public XBreakpointCustomPropertiesPanel<XLineBreakpoint<JavaFieldBreakpointProperties>> createCustomPropertiesPanel() { + return new FieldBreakpointPropertiesPanel(); + } + + @Nullable + @Override + public JavaFieldBreakpointProperties createProperties() { + return new JavaFieldBreakpointProperties(); + } + + @Nullable + @Override + public JavaFieldBreakpointProperties createBreakpointProperties(@NotNull VirtualFile file, int line) { + return new JavaFieldBreakpointProperties(); + } + + @Nullable + @Override + public XLineBreakpoint<JavaFieldBreakpointProperties> addBreakpoint(final Project project, JComponent parentComponent) { + final Ref<XLineBreakpoint> result = Ref.create(null); + AddFieldBreakpointDialog dialog = new AddFieldBreakpointDialog(project) { + protected boolean validateData() { + final String className = getClassName(); + if (className.length() == 0) { + Messages.showMessageDialog(project, DebuggerBundle.message("error.field.breakpoint.class.name.not.specified"), + DebuggerBundle.message("add.field.breakpoint.dialog.title"), Messages.getErrorIcon()); + return false; + } + final String fieldName = getFieldName(); + if (fieldName.length() == 0) { + Messages.showMessageDialog(project, DebuggerBundle.message("error.field.breakpoint.field.name.not.specified"), + DebuggerBundle.message("add.field.breakpoint.dialog.title"), Messages.getErrorIcon()); + return false; + } + PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)); + if (psiClass != null) { + final PsiFile psiFile = psiClass.getContainingFile(); + Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); + if(document != null) { + PsiField field = psiClass.findFieldByName(fieldName, true); + if(field != null) { + final int line = document.getLineNumber(field.getTextOffset()); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + XLineBreakpoint<JavaFieldBreakpointProperties> fieldBreakpoint = XDebuggerManager.getInstance(project).getBreakpointManager() + .addLineBreakpoint(JavaFieldBreakpointType.this, psiFile.getVirtualFile().getUrl(), line, new JavaFieldBreakpointProperties(fieldName, className)); + result.set(fieldBreakpoint); + } + }); + return true; + } + else { + Messages.showMessageDialog(project, + DebuggerBundle.message("error.field.breakpoint.field.not.found", className, fieldName, fieldName), + CommonBundle.getErrorTitle(), + Messages.getErrorIcon() + ); + } + } + } else { + Messages.showMessageDialog(project, + DebuggerBundle.message("error.field.breakpoint.class.sources.not.found", className, fieldName, className), + CommonBundle.getErrorTitle(), + Messages.getErrorIcon() + ); + } + return false; + } + }; + dialog.show(); + return result.get(); + } + + @Override + public Breakpoint createJavaBreakpoint(Project project, XBreakpoint breakpoint) { + return new FieldBreakpoint(project, breakpoint); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointType.java new file mode 100644 index 000000000000..99a37d4d3fbe --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointType.java @@ -0,0 +1,92 @@ +/* + * 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. + * 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.debugger.ui.breakpoints; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.HelpID; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.xdebugger.XDebuggerUtil; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; +import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties; + +import javax.swing.*; +import java.util.List; + +/** + * Base class for java line-connected exceptions (line, method, field) + * @author egor + */ +public class JavaLineBreakpointType extends JavaLineBreakpointTypeBase<JavaBreakpointProperties> implements JavaBreakpointType { + public JavaLineBreakpointType() { + super("java-line", DebuggerBundle.message("line.breakpoints.tab.title")); + } + + @NotNull + @Override + public Icon getEnabledIcon() { + return AllIcons.Debugger.Db_set_breakpoint; + } + + @NotNull + @Override + public Icon getDisabledIcon() { + return AllIcons.Debugger.Db_disabled_breakpoint; + } + + //@Override + protected String getHelpID() { + return HelpID.LINE_BREAKPOINTS; + } + + //@Override + public String getDisplayName() { + return DebuggerBundle.message("line.breakpoints.tab.title"); + } + + @Override + public List<XBreakpointGroupingRule<XLineBreakpoint<JavaBreakpointProperties>, ?>> getGroupingRules() { + return XDebuggerUtil.getInstance().getGroupingByFileRuleAsList(); + } + + @Nullable + @Override + public JavaBreakpointProperties createProperties() { + return new JavaLineBreakpointProperties(); + } + + @Nullable + @Override + public JavaBreakpointProperties createBreakpointProperties(@NotNull VirtualFile file, int line) { + return new JavaLineBreakpointProperties(); + } + + @Override + public Breakpoint createJavaBreakpoint(Project project, XBreakpoint breakpoint) { + return new LineBreakpoint(project, breakpoint); + } + + @Override + public int getPriority() { + return 100; + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java new file mode 100644 index 000000000000..08b26bb7280e --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java @@ -0,0 +1,157 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.ui.breakpoints; + +import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.engine.DebuggerUtils; +import com.intellij.debugger.ui.JavaDebuggerSupport; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Processor; +import com.intellij.xdebugger.XDebuggerUtil; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.XLineBreakpointType; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.JavaDebuggerEditorsProvider; +import org.jetbrains.java.debugger.breakpoints.JavaBreakpointFiltersPanel; +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; + +/** + * Base class for java line-connected exceptions (line, method, field) + * @author egor + */ +public abstract class JavaLineBreakpointTypeBase<P extends JavaBreakpointProperties> extends XLineBreakpointType<P> { + public JavaLineBreakpointTypeBase(@NonNls @NotNull String id, @Nls @NotNull String title) { + super(id, title); + } + + @Override + public boolean isAddBreakpointButtonVisible() { + return true; + } + + @Override + public final boolean isSuspendThreadSupported() { + return true; + } + + @Nullable + @Override + public final XBreakpointCustomPropertiesPanel<XLineBreakpoint<P>> createCustomRightPropertiesPanel(@NotNull Project project) { + return new JavaBreakpointFiltersPanel<P, XLineBreakpoint<P>>(project); + } + + @Nullable + @Override + public final XDebuggerEditorsProvider getEditorsProvider(@NotNull XLineBreakpoint<P> breakpoint, @NotNull Project project) { + return new JavaDebuggerEditorsProvider(); + } + + @Override + public String getDisplayText(XLineBreakpoint<P> breakpoint) { + BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(JavaDebuggerSupport.getCurrentProject()).getBreakpointManager(); + BreakpointWithHighlighter javaBreakpoint = (BreakpointWithHighlighter)breakpointManager.findBreakpoint(breakpoint); + if (javaBreakpoint != null) { + return javaBreakpoint.getDescription(); + } + else { + return super.getDisplayText(breakpoint); + } + } + + @Override + public final boolean canPutAt(@NotNull VirtualFile file, final int line, @NotNull Project project) { + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + // JSPX supports jvm debugging, but not in XHTML files + // JS has it's own breakpoints + if (psiFile == null || psiFile.getVirtualFile().getFileType() == StdFileTypes.XHTML || psiFile.getVirtualFile().getFileType() == StdFileTypes.JS) { + return false; + } + + FileType fileType = psiFile.getFileType(); + if (!StdFileTypes.CLASS.equals(fileType) && + !DebuggerUtils.supportsJVMDebugging(fileType) && + !DebuggerUtils.supportsJVMDebugging(psiFile)) { + return false; + } + + final Document document = FileDocumentManager.getInstance().getDocument(file); + final Ref<Class<? extends JavaLineBreakpointTypeBase>> result = Ref.create(); + XDebuggerUtil.getInstance().iterateLine(project, document, line, new Processor<PsiElement>() { + @Override + public boolean process(PsiElement element) { + // avoid comments + if ((element instanceof PsiWhiteSpace) || (PsiTreeUtil.getParentOfType(element, PsiComment.class, false) != null)) { + return true; + } + PsiElement parent = element; + while(element != null) { + // skip modifiers + if (element instanceof PsiModifierList) { + element = element.getParent(); + continue; + } + + final int offset = element.getTextOffset(); + if (offset >= 0) { + if (document.getLineNumber(offset) != line) { + break; + } + } + parent = element; + element = element.getParent(); + } + + if(parent instanceof PsiMethod) { + if (parent.getTextRange().getEndOffset() >= document.getLineEndOffset(line)) { + PsiCodeBlock body = ((PsiMethod)parent).getBody(); + if (body != null) { + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0 && document.getLineNumber(statements[0].getTextOffset()) == line) { + result.set(JavaLineBreakpointType.class); + } + } + } + if (result.isNull()) { + result.set(JavaMethodBreakpointType.class); + } + } + else if (parent instanceof PsiField) { + if (result.isNull()) { + result.set(JavaFieldBreakpointType.class); + } + } + else { + result.set(JavaLineBreakpointType.class); + } + return true; + } + }); + return result.get() == getClass(); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaMethodBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaMethodBreakpointType.java new file mode 100644 index 000000000000..94c3c77d80ce --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaMethodBreakpointType.java @@ -0,0 +1,122 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.ui.breakpoints; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.HelpID; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.StringBuilderSpinAllocator; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaMethodBreakpointProperties; + +import javax.swing.*; + +/** + * @author Eugene Zhuravlev + * Date: Apr 26, 2005 + */ +public class JavaMethodBreakpointType extends JavaLineBreakpointTypeBase<JavaMethodBreakpointProperties> implements JavaBreakpointType { + public JavaMethodBreakpointType() { + super("java-method", DebuggerBundle.message("method.breakpoints.tab.title")); + } + + @NotNull + @Override + public Icon getEnabledIcon() { + return AllIcons.Debugger.Db_method_breakpoint; + } + + @NotNull + @Override + public Icon getDisabledIcon() { + return AllIcons.Debugger.Db_disabled_method_breakpoint; + } + + //@Override + protected String getHelpID() { + return HelpID.METHOD_BREAKPOINTS; + } + + @Override + public boolean isAddBreakpointButtonVisible() { + return false; + } + + //@Override + public String getDisplayName() { + return DebuggerBundle.message("method.breakpoints.tab.title"); + } + + @Override + public String getShortText(XLineBreakpoint<JavaMethodBreakpointProperties> breakpoint) { + return getText(breakpoint); + } + + static String getText(XBreakpoint<JavaMethodBreakpointProperties> breakpoint) { + final StringBuilder buffer = StringBuilderSpinAllocator.alloc(); + try { + //if(isValid()) { + final String className = breakpoint.getProperties().myClassPattern; + final boolean classNameExists = className != null && className.length() > 0; + if (classNameExists) { + buffer.append(className); + } + if(breakpoint.getProperties().myMethodName != null) { + if (classNameExists) { + buffer.append("."); + } + buffer.append(breakpoint.getProperties().myMethodName); + } + //} + //else { + // buffer.append(DebuggerBundle.message("status.breakpoint.invalid")); + //} + return buffer.toString(); + } + finally { + StringBuilderSpinAllocator.dispose(buffer); + } + } + + @Nullable + @Override + public XBreakpointCustomPropertiesPanel createCustomPropertiesPanel() { + return new MethodBreakpointPropertiesPanel(); + } + + @Nullable + @Override + public JavaMethodBreakpointProperties createProperties() { + return new JavaMethodBreakpointProperties(); + } + + @Nullable + @Override + public JavaMethodBreakpointProperties createBreakpointProperties(@NotNull VirtualFile file, int line) { + return new JavaMethodBreakpointProperties(); + } + + @Override + public Breakpoint createJavaBreakpoint(Project project, XBreakpoint breakpoint) { + return new MethodBreakpoint(project, breakpoint); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaWildcardMethodBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaWildcardMethodBreakpointType.java new file mode 100644 index 000000000000..dd28ee241f1a --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaWildcardMethodBreakpointType.java @@ -0,0 +1,107 @@ +/* + * 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. + * 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.debugger.ui.breakpoints; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.HelpID; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.xdebugger.XDebuggerManager; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaMethodBreakpointProperties; + +import javax.swing.*; + +/** + * @author Egor + */ +public class JavaWildcardMethodBreakpointType extends JavaBreakpointTypeBase<JavaMethodBreakpointProperties> implements JavaBreakpointType { + public JavaWildcardMethodBreakpointType() { + super("java-wildcard-method", DebuggerBundle.message("method.breakpoints.tab.title")); + } + + @NotNull + @Override + public Icon getEnabledIcon() { + return AllIcons.Debugger.Db_method_breakpoint; + } + + @NotNull + @Override + public Icon getDisabledIcon() { + return AllIcons.Debugger.Db_disabled_method_breakpoint; + } + + //@Override + protected String getHelpID() { + return HelpID.METHOD_BREAKPOINTS; + } + + //@Override + public String getDisplayName() { + return DebuggerBundle.message("method.breakpoints.tab.title"); + } + + @Override + public String getDisplayText(XBreakpoint<JavaMethodBreakpointProperties> breakpoint) { + return JavaMethodBreakpointType.getText(breakpoint); + } + + @Nullable + @Override + public XBreakpointCustomPropertiesPanel<XBreakpoint<JavaMethodBreakpointProperties>> createCustomPropertiesPanel() { + return new MethodBreakpointPropertiesPanel(); + } + + //@Override + //public Key<MethodBreakpoint> getBreakpointCategory() { + // return MethodBreakpoint.CATEGORY; + //} + + @Nullable + @Override + public JavaMethodBreakpointProperties createProperties() { + return new JavaMethodBreakpointProperties(); + } + + @Nullable + @Override + public XBreakpoint<JavaMethodBreakpointProperties> addBreakpoint(final Project project, JComponent parentComponent) { + final AddWildcardBreakpointDialog dialog = new AddWildcardBreakpointDialog(project); + dialog.show(); + if (!dialog.isOK()) { + return null; + } + return ApplicationManager.getApplication().runWriteAction(new Computable<XBreakpoint<JavaMethodBreakpointProperties>>() { + @Override + public XBreakpoint<JavaMethodBreakpointProperties> compute() { + return XDebuggerManager.getInstance(project).getBreakpointManager().addBreakpoint(JavaWildcardMethodBreakpointType.this, new JavaMethodBreakpointProperties( + dialog.getClassPattern(), + dialog.getMethodName())); + } + }); + } + + @Override + public Breakpoint createJavaBreakpoint(Project project, XBreakpoint breakpoint) { + return new WildcardMethodBreakpoint(project, breakpoint); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java index 307b9629b99f..2b3239122373 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java @@ -54,6 +54,7 @@ import com.intellij.util.Processor; import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.containers.ContainerUtil; import com.intellij.xdebugger.XDebuggerUtil; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.sun.jdi.*; import com.sun.jdi.event.LocatableEvent; import com.sun.jdi.request.BreakpointRequest; @@ -74,12 +75,8 @@ public class LineBreakpoint extends BreakpointWithHighlighter { private String myOwnerMethodName; public static final @NonNls Key<LineBreakpoint> CATEGORY = BreakpointCategory.lookup("line_breakpoints"); - protected LineBreakpoint(Project project) { - super(project); - } - - public LineBreakpoint(Project project, RangeHighlighter highlighter) { - super(project, highlighter); + protected LineBreakpoint(Project project, XBreakpoint xBreakpoint) { + super(project, xBreakpoint); } @Override @@ -95,7 +92,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { @Override protected Icon getSetIcon(boolean isMuted) { - if (REMOVE_AFTER_HIT) { + if (isRemoveAfterHit()) { return isMuted ? AllIcons.Debugger.Db_muted_temporary_breakpoint : AllIcons.Debugger.Db_temporary_breakpoint; } return isMuted? AllIcons.Debugger.Db_muted_breakpoint : AllIcons.Debugger.Db_set_breakpoint; @@ -108,7 +105,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { @Override protected Icon getVerifiedIcon(boolean isMuted) { - if (REMOVE_AFTER_HIT) { + if (isRemoveAfterHit()) { return isMuted ? AllIcons.Debugger.Db_muted_temporary_breakpoint : AllIcons.Debugger.Db_temporary_breakpoint; } return isMuted? AllIcons.Debugger.Db_muted_verified_breakpoint : AllIcons.Debugger.Db_verified_breakpoint; @@ -349,9 +346,8 @@ public class LineBreakpoint extends BreakpointWithHighlighter { } private String getDisplayInfoInternal(boolean showPackageInfo, int totalTextLength) { - final RangeHighlighter highlighter = getHighlighter(); - if(highlighter != null && highlighter.isValid() && isValid()) { - final int lineNumber = (highlighter.getDocument().getLineNumber(highlighter.getStartOffset()) + 1); + if(isValid()) { + final int lineNumber = getSourcePosition().getLine() + 1; String className = getClassName(); final boolean hasClassInfo = className != null && className.length() > 0; final String methodName = getMethodName(); @@ -471,24 +467,19 @@ public class LineBreakpoint extends BreakpointWithHighlighter { return ContextUtil.getContextElement(getSourcePosition()); } - public static LineBreakpoint create(@NotNull Project project, @NotNull Document document, int lineIndex) { - final RangeHighlighter highlighter = createHighlighter(project, document, lineIndex); - if (highlighter == null) { - return null; - } - - LineBreakpoint breakpoint = new LineBreakpoint(project, highlighter); + public static LineBreakpoint create(@NotNull Project project, XBreakpoint xBreakpoint) { + LineBreakpoint breakpoint = new LineBreakpoint(project, xBreakpoint); return (LineBreakpoint)breakpoint.init(); } - @Override - public boolean canMoveTo(SourcePosition position) { - if (!super.canMoveTo(position)) { - return false; - } - final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(position.getFile()); - return canAddLineBreakpoint(myProject, document, position.getLine()); - } + //@Override + //public boolean canMoveTo(SourcePosition position) { + // if (!super.canMoveTo(position)) { + // return false; + // } + // final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(position.getFile()); + // return canAddLineBreakpoint(myProject, document, position.getLine()); + //} public static boolean canAddLineBreakpoint(Project project, final Document document, final int lineIndex) { if (lineIndex < 0 || lineIndex >= document.getLineCount()) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java deleted file mode 100644 index 0042074dc798..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.ui.breakpoints; - -import com.intellij.debugger.DebuggerBundle; -import com.intellij.debugger.HelpID; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import org.jdom.Element; - -import javax.swing.*; - -/** - * @author Eugene Zhuravlev - * Date: Apr 26, 2005 - */ -public class LineBreakpointFactory extends BreakpointFactory { - @Override - public Breakpoint createBreakpoint(Project project, final Element element) { - return new LineBreakpoint(project); - } - - @Override - public Icon getIcon() { - return AllIcons.Debugger.Db_set_breakpoint; - } - - @Override - public Icon getDisabledIcon() { - return AllIcons.Debugger.Db_disabled_breakpoint; - } - - @Override - protected String getHelpID() { - return HelpID.LINE_BREAKPOINTS; - } - - @Override - public String getDisplayName() { - return DebuggerBundle.message("line.breakpoints.tab.title"); - } - - @Override - public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) { - return new LineBreakpointPropertiesPanel(project, compact); - } - - @Override - public Key<LineBreakpoint> getBreakpointCategory() { - return LineBreakpoint.CATEGORY; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java index 90a839d425d4..be10d56113f8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java @@ -38,10 +38,13 @@ import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.Key; import com.intellij.psi.*; import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.text.CharArrayUtil; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.Location; import com.sun.jdi.Method; @@ -52,31 +55,29 @@ import com.sun.jdi.event.MethodExitEvent; import com.sun.jdi.request.EventRequest; import com.sun.jdi.request.MethodEntryRequest; import com.sun.jdi.request.MethodExitRequest; +import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaMethodBreakpointProperties; import javax.swing.*; import java.util.Iterator; import java.util.Set; -public class MethodBreakpoint extends BreakpointWithHighlighter { +public class MethodBreakpoint extends BreakpointWithHighlighter<JavaMethodBreakpointProperties> { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.MethodBreakpoint"); - public boolean WATCH_ENTRY = true; - public boolean WATCH_EXIT = true; - - @Nullable private String myMethodName; @Nullable private JVMName mySignature; private boolean myIsStatic; public static final @NonNls Key<MethodBreakpoint> CATEGORY = BreakpointCategory.lookup("method_breakpoints"); - protected MethodBreakpoint(@NotNull Project project) { - super(project); + protected MethodBreakpoint(@NotNull Project project, XBreakpoint breakpoint) { + super(project, breakpoint); } private MethodBreakpoint(@NotNull Project project, @NotNull RangeHighlighter highlighter) { - super(project, highlighter); + super(project, highlighter, null); } public boolean isStatic() { @@ -104,21 +105,25 @@ public class MethodBreakpoint extends BreakpointWithHighlighter { } public boolean isValid() { - return super.isValid() && myMethodName != null; + return super.isValid() && getMethodName() != null; } protected void reload(@NotNull PsiFile psiFile) { - myMethodName = null; + setMethodName(null); mySignature = null; MethodDescriptor descriptor = getMethodDescriptor(myProject, psiFile, getSourcePosition()); if (descriptor != null) { - myMethodName = descriptor.methodName; + setMethodName(descriptor.methodName); mySignature = descriptor.methodSignature; myIsStatic = descriptor.isStatic; } + PsiClass psiClass = getPsiClass(); + if (psiClass != null) { + getProperties().myClassPattern = psiClass.getQualifiedName(); + } if (myIsStatic) { - INSTANCE_FILTERS_ENABLED = false; + setInstanceFiltersEnabled(false); } } @@ -130,7 +135,7 @@ public class MethodBreakpoint extends BreakpointWithHighlighter { String signature = method.signature(); String name = method.name(); - if (myMethodName.equals(name) && mySignature.getName(debugProcess).equals(signature)) { + if (getMethodName().equals(name) && mySignature.getName(debugProcess).equals(signature)) { hasMethod = true; break; } @@ -144,7 +149,7 @@ public class MethodBreakpoint extends BreakpointWithHighlighter { } RequestManagerImpl requestManager = debugProcess.getRequestsManager(); - if (WATCH_ENTRY) { + if (isWatchEntry()) { MethodEntryRequest entryRequest = (MethodEntryRequest)findRequest(debugProcess, MethodEntryRequest.class); if (entryRequest == null) { entryRequest = requestManager.createMethodEntryRequest(this); @@ -157,7 +162,7 @@ public class MethodBreakpoint extends BreakpointWithHighlighter { entryRequest.addClassFilter(classType); debugProcess.getRequestsManager().enableRequest(entryRequest); } - if (WATCH_EXIT) { + if (isWatchExit()) { MethodExitRequest exitRequest = (MethodExitRequest)findRequest(debugProcess, MethodExitRequest.class); if (exitRequest == null) { exitRequest = requestManager.createMethodExitRequest(this); @@ -256,11 +261,11 @@ public class MethodBreakpoint extends BreakpointWithHighlighter { if (classNameExists) { buffer.append(className); } - if(myMethodName != null) { + if(getMethodName() != null) { if (classNameExists) { buffer.append("."); } - buffer.append(myMethodName); + buffer.append(getMethodName()); } } else { @@ -281,16 +286,16 @@ public class MethodBreakpoint extends BreakpointWithHighlighter { } public boolean matchesEvent(@NotNull final LocatableEvent event, final DebugProcessImpl process) throws EvaluateException { - if (myMethodName == null || mySignature == null) { + if (getMethodName() == null || mySignature == null) { return false; } final Method method = event.location().method(); - return method != null && method.name().equals(myMethodName) && method.signature().equals(mySignature.getName(process)); + return method != null && method.name().equals(getMethodName()) && method.signature().equals(mySignature.getName(process)); } @Nullable - public static MethodBreakpoint create(@NotNull Project project, @NotNull Document document, int lineIndex) { - final MethodBreakpoint breakpoint = new MethodBreakpoint(project, createHighlighter(project, document, lineIndex)); + public static MethodBreakpoint create(@NotNull Project project, XBreakpoint xBreakpoint) { + final MethodBreakpoint breakpoint = new MethodBreakpoint(project, xBreakpoint); return (MethodBreakpoint)breakpoint.init(); } @@ -362,6 +367,19 @@ public class MethodBreakpoint extends BreakpointWithHighlighter { return null; } + @Override + public void readExternal(@NotNull Element breakpointNode) throws InvalidDataException { + super.readExternal(breakpointNode); + try { + getProperties().WATCH_ENTRY = Boolean.valueOf(JDOMExternalizerUtil.readField(breakpointNode, "WATCH_ENTRY")); + } catch (Exception e) { + } + try { + getProperties().WATCH_EXIT = Boolean.valueOf(JDOMExternalizerUtil.readField(breakpointNode, "WATCH_EXIT")); + } catch (Exception e) { + } + } + public String toString() { return getDescription(); } @@ -376,6 +394,23 @@ public class MethodBreakpoint extends BreakpointWithHighlighter { return false; } + private boolean isWatchEntry() { + return getProperties().WATCH_ENTRY; + } + + private boolean isWatchExit() { + return getProperties().WATCH_EXIT; + } + + @Nullable + private String getMethodName() { + return getProperties().myMethodName; + } + + private void setMethodName(@Nullable String methodName) { + getProperties().myMethodName = methodName; + } + private static final class MethodDescriptor { String methodName; JVMName methodSignature; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java deleted file mode 100644 index a08e2a123ae6..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.ui.breakpoints; - -import com.intellij.debugger.DebuggerBundle; -import com.intellij.debugger.DebuggerManagerEx; -import com.intellij.debugger.HelpID; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import org.jdom.Element; - -import javax.swing.*; - -/** - * @author Eugene Zhuravlev - * Date: Apr 26, 2005 - */ -public class MethodBreakpointFactory extends BreakpointFactory{ - @Override - public Breakpoint createBreakpoint(Project project, final Element element) { - return element.getAttributeValue(WildcardMethodBreakpoint.JDOM_LABEL) != null? new WildcardMethodBreakpoint(project) : new MethodBreakpoint(project); - } - - @Override - public Icon getIcon() { - return AllIcons.Debugger.Db_method_breakpoint; - } - - @Override - public Icon getDisabledIcon() { - return AllIcons.Debugger.Db_disabled_method_breakpoint; - } - - @Override - protected String getHelpID() { - return HelpID.METHOD_BREAKPOINTS; - } - - @Override - public String getDisplayName() { - return DebuggerBundle.message("method.breakpoints.tab.title"); - } - - @Override - public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) { - return new MethodBreakpointPropertiesPanel(project, compact); - } - - @Override - public Key<MethodBreakpoint> getBreakpointCategory() { - return MethodBreakpoint.CATEGORY; - } - - @Override - public boolean canAddBreakpoints() { - return true; - } - - @Override - public WildcardMethodBreakpoint addBreakpoint(Project project) { - AddWildcardBreakpointDialog dialog = new AddWildcardBreakpointDialog(project); - dialog.show(); - WildcardMethodBreakpoint methodBreakpoint; - methodBreakpoint = !dialog.isOK() - ? null - : DebuggerManagerEx.getInstanceEx(project).getBreakpointManager() - .addMethodBreakpoint(dialog.getClassPattern(), dialog.getMethodName()); - return methodBreakpoint; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointPropertiesPanel.java index c50b6995d038..bf7419264105 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointPropertiesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointPropertiesPanel.java @@ -21,24 +21,30 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.debugger.DebuggerBundle; -import com.intellij.openapi.project.Project; import com.intellij.ui.IdeBorderFactory; import com.intellij.util.ui.DialogUtil; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.java.debugger.breakpoints.properties.JavaMethodBreakpointProperties; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -public class MethodBreakpointPropertiesPanel extends BreakpointPropertiesPanel { +public class MethodBreakpointPropertiesPanel extends XBreakpointCustomPropertiesPanel<XBreakpoint<JavaMethodBreakpointProperties>> { private JCheckBox myWatchEntryCheckBox; private JCheckBox myWatchExitCheckBox; - public MethodBreakpointPropertiesPanel(final Project project, boolean compact) { - super(project, MethodBreakpoint.CATEGORY, compact); - } + //public MethodBreakpointPropertiesPanel(final Project project, boolean compact) { + // super(project, MethodBreakpoint.CATEGORY, compact); + //} + - protected JComponent createSpecialBox() { + @NotNull + @Override + public JComponent getComponent() { JPanel _panel, _panel0; myWatchEntryCheckBox = new JCheckBox(DebuggerBundle.message("label.method.breakpoint.properties.panel.method.entry")); @@ -86,31 +92,15 @@ public class MethodBreakpointPropertiesPanel extends BreakpointPropertiesPanel { return _panel; } - public void initFrom(Breakpoint breakpoint, boolean moreOptionsVisible) { - super.initFrom(breakpoint, moreOptionsVisible); - if (breakpoint instanceof MethodBreakpoint) { - MethodBreakpoint methodBreakpoint = (MethodBreakpoint)breakpoint; - myWatchEntryCheckBox.setSelected(methodBreakpoint.WATCH_ENTRY); - myWatchExitCheckBox.setSelected(methodBreakpoint.WATCH_EXIT); - } - else if (breakpoint instanceof WildcardMethodBreakpoint){ - final WildcardMethodBreakpoint methodBreakpoint = ((WildcardMethodBreakpoint)breakpoint); - myWatchEntryCheckBox.setSelected(methodBreakpoint.WATCH_ENTRY); - myWatchExitCheckBox.setSelected(methodBreakpoint.WATCH_EXIT); - } + @Override + public void loadFrom(@NotNull XBreakpoint<JavaMethodBreakpointProperties> breakpoint) { + myWatchEntryCheckBox.setSelected(breakpoint.getProperties().WATCH_ENTRY); + myWatchExitCheckBox.setSelected(breakpoint.getProperties().WATCH_EXIT); } - public void saveTo(Breakpoint breakpoint) { - if (breakpoint instanceof MethodBreakpoint) { - MethodBreakpoint methodBreakpoint = (MethodBreakpoint)breakpoint; - methodBreakpoint.WATCH_ENTRY = myWatchEntryCheckBox.isSelected(); - methodBreakpoint.WATCH_EXIT = myWatchExitCheckBox.isSelected(); - } - else if (breakpoint instanceof WildcardMethodBreakpoint){ - final WildcardMethodBreakpoint methodBreakpoint = ((WildcardMethodBreakpoint)breakpoint); - methodBreakpoint.WATCH_ENTRY = myWatchEntryCheckBox.isSelected(); - methodBreakpoint.WATCH_EXIT = myWatchExitCheckBox.isSelected(); - } - super.saveTo(breakpoint); + @Override + public void saveTo(@NotNull XBreakpoint<JavaMethodBreakpointProperties> breakpoint) { + breakpoint.getProperties().WATCH_ENTRY = myWatchEntryCheckBox.isSelected(); + breakpoint.getProperties().WATCH_EXIT = myWatchExitCheckBox.isSelected(); } }
\ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java index 82f617a14f6b..19a187da03c4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java @@ -18,10 +18,11 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,18 +32,11 @@ import org.jetbrains.annotations.Nullable; */ public class RunToCursorBreakpoint extends LineBreakpoint { private final boolean myRestoreBreakpoints; - @Nullable private final SourcePosition myCustomPosition; - - protected RunToCursorBreakpoint(@NotNull Project project, @NotNull RangeHighlighter highlighter, boolean restoreBreakpoints) { - super(project, highlighter); - setVisible(false); - myRestoreBreakpoints = restoreBreakpoints; - myCustomPosition = null; - } + private String mySuspendPolicy; protected RunToCursorBreakpoint(@NotNull Project project, @NotNull SourcePosition pos, boolean restoreBreakpoints) { - super(project); + super(project, null); myCustomPosition = pos; setVisible(false); myRestoreBreakpoints = restoreBreakpoints; @@ -50,7 +44,51 @@ public class RunToCursorBreakpoint extends LineBreakpoint { @Override public SourcePosition getSourcePosition() { - return myCustomPosition != null ? myCustomPosition : super.getSourcePosition(); + return myCustomPosition; + } + + @Override + public void reload() { + } + + @Override + public String getSuspendPolicy() { + return mySuspendPolicy; + } + + public void setSuspendPolicy(String policy) { + mySuspendPolicy = policy; + } + + protected boolean isLogEnabled() { + return false; + } + + @Override + protected boolean isLogExpressionEnabled() { + return false; + } + + @Override + public boolean isEnabled() { + return true; + } + + public boolean isCountFilterEnabled() { + return false; + } + + public boolean isClassFiltersEnabled() { + return false; + } + + public boolean isInstanceFiltersEnabled() { + return false; + } + + @Override + protected boolean isConditionEnabled() { + return false; } public boolean isRestoreBreakpoints() { @@ -63,6 +101,11 @@ public class RunToCursorBreakpoint extends LineBreakpoint { } @Override + public boolean isValid() { + return true; + } + + @Override protected boolean isMuted(@NotNull final DebugProcessImpl debugProcess) { return false; // always enabled } @@ -74,17 +117,9 @@ public class RunToCursorBreakpoint extends LineBreakpoint { return null; } - final RangeHighlighter highlighter = createHighlighter(project, document, lineIndex); - if (highlighter == null) { - return null; - } - - final RunToCursorBreakpoint breakpoint = new RunToCursorBreakpoint(project, highlighter, restoreBreakpoints); - final RangeHighlighter h = breakpoint.getHighlighter(); - if (h != null) { - h.dispose(); - } + PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile); + SourcePosition pos = SourcePosition.createFromLine(psiFile, lineIndex); - return (RunToCursorBreakpoint)breakpoint.init(); + return new RunToCursorBreakpoint(project, pos, restoreBreakpoints); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/StepIntoBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/StepIntoBreakpoint.java index 6e39e5ac1d29..af7d6755523a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/StepIntoBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/StepIntoBreakpoint.java @@ -153,7 +153,7 @@ public class StepIntoBreakpoint extends RunToCursorBreakpoint { if (pos != null) { final StepIntoBreakpoint breakpoint = new StepIntoBreakpoint(project, pos, filter); breakpoint.init(); - breakpoint.LOG_ENABLED = false; + breakpoint.setLogEnabled(false); return breakpoint; } return null; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java index f6c0dc3c3ab2..295fddbaf187 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java @@ -23,15 +23,20 @@ import com.intellij.debugger.engine.DebuggerManagerThreadImpl; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.engine.requests.RequestManagerImpl; +import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.icons.AllIcons; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.StringBuilderSpinAllocator; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.Location; import com.sun.jdi.Method; @@ -45,37 +50,33 @@ import com.sun.jdi.request.MethodExitRequest; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.properties.JavaMethodBreakpointProperties; import javax.swing.*; import java.util.Iterator; import java.util.Set; -public class WildcardMethodBreakpoint extends Breakpoint { +public class WildcardMethodBreakpoint extends Breakpoint<JavaMethodBreakpointProperties> { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.ExceptionBreakpoint"); - public boolean WATCH_ENTRY = true; - public boolean WATCH_EXIT = true; - private String myClassPattern; - private String myMethodName; - public static final String JDOM_LABEL = "wildcard_breakpoint"; - public WildcardMethodBreakpoint(Project project) { - super(project); + public WildcardMethodBreakpoint(Project project, XBreakpoint breakpoint) { + super(project, breakpoint); } public Key<MethodBreakpoint> getCategory() { return MethodBreakpoint.CATEGORY; } - protected WildcardMethodBreakpoint(Project project, @NotNull String classPattern, @NotNull String methodName) { - super(project); - myClassPattern = classPattern; - myMethodName = methodName; + protected WildcardMethodBreakpoint(Project project, @NotNull String classPattern, @NotNull String methodName, XBreakpoint breakpoint) { + super(project, breakpoint); + setClassPattern(classPattern); + setMethodName(methodName); } public String getClassName() { - return myClassPattern; + return getClassPattern(); } public @Nullable String getShortClassName() { @@ -83,11 +84,15 @@ public class WildcardMethodBreakpoint extends Breakpoint { } public String getMethodName() { - return myMethodName; + return getProperties().myMethodName; } public PsiClass getPsiClass() { - return null; + return PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(new Computable<PsiClass>() { + public PsiClass compute() { + return getClassName() != null ? DebuggerUtilsEx.findClass(getClassName(), myProject, GlobalSearchScope.allScope(myProject)) : null; + } + }); } public String getDisplayName() { @@ -96,9 +101,9 @@ public class WildcardMethodBreakpoint extends Breakpoint { } final StringBuilder buffer = StringBuilderSpinAllocator.alloc(); try { - buffer.append(myClassPattern); + buffer.append(getClassPattern()); buffer.append("."); - buffer.append(myMethodName); + buffer.append(getMethodName()); buffer.append("()"); return buffer.toString(); } @@ -108,7 +113,7 @@ public class WildcardMethodBreakpoint extends Breakpoint { } public Icon getIcon() { - if (!ENABLED) { + if (!isEnabled()) { final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this); return master == null? AllIcons.Debugger.Db_disabled_method_breakpoint : AllIcons.Debugger.Db_dep_method_breakpoint; } @@ -124,12 +129,12 @@ public class WildcardMethodBreakpoint extends Breakpoint { public void createRequest(DebugProcessImpl debugProcess) { DebuggerManagerThreadImpl.assertIsManagerThread(); - if (!ENABLED || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { + if (!isEnabled() || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { return; } try { RequestManagerImpl requestManager = debugProcess.getRequestsManager(); - if (WATCH_ENTRY) { + if (isWatchEntry()) { MethodEntryRequest entryRequest = (MethodEntryRequest)findRequest(debugProcess, MethodEntryRequest.class); if (entryRequest == null) { entryRequest = requestManager.createMethodEntryRequest(this); @@ -137,10 +142,10 @@ public class WildcardMethodBreakpoint extends Breakpoint { else { entryRequest.disable(); } - entryRequest.addClassFilter(myClassPattern); + entryRequest.addClassFilter(getClassPattern()); debugProcess.getRequestsManager().enableRequest(entryRequest); } - if (WATCH_EXIT) { + if (isWatchExit()) { MethodExitRequest exitRequest = (MethodExitRequest)findRequest(debugProcess, MethodExitRequest.class); if (exitRequest == null) { exitRequest = requestManager.createMethodExitRequest(this); @@ -148,7 +153,7 @@ public class WildcardMethodBreakpoint extends Breakpoint { else { exitRequest.disable(); } - exitRequest.addClassFilter(myClassPattern); + exitRequest.addClassFilter(getClassPattern()); debugProcess.getRequestsManager().enableRequest(exitRequest); } } @@ -212,19 +217,19 @@ public class WildcardMethodBreakpoint extends Breakpoint { } public boolean isValid() { - return myClassPattern != null && myMethodName != null; + return getClassPattern() != null && getMethodName() != null; } - @SuppressWarnings({"HardCodedStringLiteral"}) public void writeExternal(Element parentNode) throws WriteExternalException { - super.writeExternal(parentNode); - parentNode.setAttribute(JDOM_LABEL, "true"); - if (myClassPattern != null) { - parentNode.setAttribute("class_name", myClassPattern); - } - if (myMethodName != null) { - parentNode.setAttribute("method_name", myMethodName); - } - } + //@SuppressWarnings({"HardCodedStringLiteral"}) public void writeExternal(Element parentNode) throws WriteExternalException { + // super.writeExternal(parentNode); + // parentNode.setAttribute(JDOM_LABEL, "true"); + // if (getClassPattern() != null) { + // parentNode.setAttribute("class_name", getClassPattern()); + // } + // if (getMethodName() != null) { + // parentNode.setAttribute("method_name", getMethodName()); + // } + //} public PsiElement getEvaluationElement() { return null; @@ -235,11 +240,20 @@ public class WildcardMethodBreakpoint extends Breakpoint { //noinspection HardCodedStringLiteral String className = parentNode.getAttributeValue("class_name"); - myClassPattern = className; + setClassPattern(className); //noinspection HardCodedStringLiteral String methodName = parentNode.getAttributeValue("method_name"); - myMethodName = methodName; + setMethodName(methodName); + + try { + getProperties().WATCH_ENTRY = Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "WATCH_ENTRY")); + } catch (Exception e) { + } + try { + getProperties().WATCH_EXIT = Boolean.valueOf(JDOMExternalizerUtil.readField(parentNode, "WATCH_EXIT")); + } catch (Exception e) { + } if(className == null || methodName == null) { throw new InvalidDataException(); @@ -248,10 +262,38 @@ public class WildcardMethodBreakpoint extends Breakpoint { public boolean matchesEvent(final LocatableEvent event){ final Method method = event.location().method(); - return method != null && myMethodName.equals(method.name()); + return method != null && getMethodName().equals(method.name()); + } + + public static WildcardMethodBreakpoint create(Project project, final String classPattern, final String methodName, XBreakpoint xBreakpoint) { + return new WildcardMethodBreakpoint(project, classPattern, methodName, xBreakpoint); + } + + private boolean isWatchEntry() { + return getProperties().WATCH_ENTRY; + } + + private void setWatchEntry(boolean WATCH_ENTRY) { + getProperties().WATCH_ENTRY = WATCH_ENTRY; + } + + private boolean isWatchExit() { + return getProperties().WATCH_EXIT; + } + + private void setWatchExit(boolean WATCH_EXIT) { + getProperties().WATCH_EXIT = WATCH_EXIT; + } + + private String getClassPattern() { + return getProperties().myClassPattern; + } + + private void setClassPattern(String classPattern) { + getProperties().myClassPattern = classPattern; } - public static WildcardMethodBreakpoint create(Project project, final String classPattern, final String methodName) { - return new WildcardMethodBreakpoint(project, classPattern, methodName); + private void setMethodName(String methodName) { + getProperties().myMethodName = methodName; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreePanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreePanel.java index 25cc97222726..c04f1bf63d67 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreePanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreePanel.java @@ -93,7 +93,7 @@ public abstract class DebuggerTreePanel extends UpdatableDebuggerView implements getTree().rebuild(context); } } - catch (VMDisconnectedException e) { + catch (VMDisconnectedException ignored) { // ignored } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java index 30306a49ae84..788cb17b477e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java @@ -83,11 +83,13 @@ public class FrameVariablesTree extends DebuggerTree { } } + @Override protected void build(DebuggerContextImpl context) { myAnyNewLocals = false; buildWhenPaused(context, new RefreshFrameTreeCommand(context)); } + @Override public void restoreNodeState(DebuggerTreeNodeImpl node) { if (myAnyNewLocals) { final NodeDescriptorImpl descriptor = node.getDescriptor(); @@ -107,6 +109,7 @@ public class FrameVariablesTree extends DebuggerTree { } + @Override protected DebuggerCommandImpl getBuildNodeCommand(final DebuggerTreeNodeImpl node) { if (node.getDescriptor() instanceof StackFrameDescriptorImpl) { return new BuildFrameTreeVariablesCommand(node); @@ -119,6 +122,7 @@ public class FrameVariablesTree extends DebuggerTree { super(stackNode); } + @Override protected void buildVariables(final StackFrameDescriptorImpl stackDescriptor, final EvaluationContextImpl evaluationContext) throws EvaluateException { final DebuggerContextImpl debuggerContext = getDebuggerContext(); final SourcePosition sourcePosition = debuggerContext.getSourcePosition(); @@ -135,6 +139,7 @@ public class FrameVariablesTree extends DebuggerTree { final EvaluationContextImpl evalContext = debuggerContext.createEvaluationContext(); final Pair<Set<String>, Set<TextWithImports>> usedVars = ApplicationManager.getApplication().runReadAction(new Computable<Pair<Set<String>, Set<TextWithImports>>>() { + @Override public Pair<Set<String>, Set<TextWithImports>> compute() { return findReferencedVars(visibleVariables.keySet(), sourcePosition, evalContext); } @@ -396,6 +401,7 @@ public class FrameVariablesTree extends DebuggerTree { super(context); } + @Override public void contextAction() throws Exception { DebuggerTreeNodeImpl rootNode; @@ -433,7 +439,7 @@ public class FrameVariablesTree extends DebuggerTree { rootNode.add(MessageDescriptor.THREAD_IS_RUNNING); } } - catch (ObjectCollectedException e) { + catch (ObjectCollectedException ignored) { rootNode.add(new MessageDescriptor(DebuggerBundle.message("label.thread.node.thread.collected", currentThread.name()))); } } @@ -448,12 +454,14 @@ public class FrameVariablesTree extends DebuggerTree { final DebuggerTreeNodeImpl rootNode1 = rootNode; DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() { + @Override public void run() { getMutableModel().setRoot(rootNode1); treeChanged(); final TreeModel model = getModel(); model.addTreeModelListener(new TreeModelAdapter() { + @Override public void treeStructureChanged(TreeModelEvent e) { final Object[] path = e.getPath(); if (path.length > 0 && path[path.length - 1] == rootNode1) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesList.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesList.java index 9967b70eb485..d0d25f1808b5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesList.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesList.java @@ -35,15 +35,18 @@ public class FramesList extends DebuggerFramesList { doInit(); } + @Override protected FramesListRenderer createListRenderer() { return new FramesListRenderer(); } + @Override protected void onFrameChanged(final Object selectedValue) { final StackFrameDescriptorImpl descriptor = selectedValue instanceof StackFrameDescriptorImpl? (StackFrameDescriptorImpl)selectedValue : null; final Method newMethod = descriptor != null? descriptor.getMethod() : null; if (!Comparing.equal(mySelectedMethod, newMethod)) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { repaint(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java index c6e62281b143..c3368cd5c4f9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java @@ -16,14 +16,14 @@ package com.intellij.debugger.ui.impl; import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl; -import com.intellij.ui.JBColor; -import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.util.Comparing; import com.intellij.ui.ColoredListCellRenderer; +import com.intellij.ui.JBColor; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.ui.UIUtil; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.xdebugger.ui.DebuggerColors; import com.sun.jdi.Method; @@ -38,6 +38,7 @@ class FramesListRenderer extends ColoredListCellRenderer { myColorScheme = EditorColorsManager.getInstance().getGlobalScheme(); } + @Override protected void customizeCellRenderer(final JList list, final Object item, final int index, final boolean selected, final boolean hasFocus) { if (!(item instanceof StackFrameDescriptorImpl)) { append(item.toString(), SimpleTextAttributes.GRAYED_ATTRIBUTES); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java index 4b3f145995b2..e059e789254b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java @@ -59,10 +59,12 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes setLvalue(!field.isFinal()); } + @Override public Field getField() { return myField; } + @Override public ObjectReference getObject() { return myObject; } @@ -131,6 +133,7 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes } } + @Override public void setAncestor(NodeDescriptor oldDescriptor) { super.setAncestor(oldDescriptor); final Boolean isPrimitive = ((FieldDescriptorImpl)oldDescriptor).myIsPrimitive; @@ -141,6 +144,7 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes } + @Override public boolean isPrimitive() { if (myIsPrimitive == null) { final Value value = getValue(); @@ -154,12 +158,13 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes return myIsPrimitive.booleanValue(); } + @Override public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); try { return (myObject != null) ? myObject.getValue(myField) : myField.declaringType().getValue(myField); } - catch (ObjectCollectedException e) { + catch (ObjectCollectedException ignored) { throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED; } } @@ -168,6 +173,7 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes return myIsStatic; } + @Override public String getName() { final String fieldName = myField.name(); if (isOuterLocalVariableValue() && NodeRendererSettings.getInstance().getClassRenderer().SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES) { @@ -180,11 +186,12 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes try { return DebuggerUtils.isSynthetic(myField) && myField.name().startsWith(OUTER_LOCAL_VAR_FIELD_PREFIX); } - catch (UnsupportedOperationException e) { + catch (UnsupportedOperationException ignored) { return false; } } + @Override public String calcValueName() { final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer(); StringBuilder buf = StringBuilderSpinAllocator.alloc(); @@ -201,6 +208,7 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes } } + @Override public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException { PsiElementFactory elementFactory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory(); String fieldName; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MessageDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MessageDescriptor.java index 026f2ad6b4b9..6f2aa4e09f0d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MessageDescriptor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MessageDescriptor.java @@ -59,17 +59,21 @@ public class MessageDescriptor extends NodeDescriptorImpl { return myKind; } + @Override public String getLabel() { return myMessage; } + @Override public boolean isExpandable() { return false; } + @Override public void setContext(EvaluationContextImpl context) { } + @Override protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener) throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); return myMessage; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java index a009733a39a9..f2f5b1c23283 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java @@ -52,15 +52,21 @@ public abstract class NodeDescriptorImpl implements NodeDescriptor { private final List<NodeDescriptorImpl> myChildren = new ArrayList<NodeDescriptorImpl>(); private static final Key<Map<ObjectReference, ValueMarkup>> MARKUP_MAP_KEY = new Key<Map<ObjectReference, ValueMarkup>>("ValueMarkupMap"); + @Override public String getName() { return null; } + @Override public <T> T getUserData(Key<T> key) { - if(myUserData == null) return null; - return (T) myUserData.get(key); + if (myUserData == null) { + return null; + } + //noinspection unchecked + return (T)myUserData.get(key); } + @Override public <T> void putUserData(Key<T> key, T value) { if(myUserData == null) { myUserData = new HashMap<Key, Object>(); @@ -91,12 +97,12 @@ public abstract class NodeDescriptorImpl implements NodeDescriptor { protected abstract String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener) throws EvaluateException; - private EvaluateException processException(Exception e) { - if(e instanceof InconsistentDebugInfoException) { + private static EvaluateException processException(Exception e) { + if (e instanceof InconsistentDebugInfoException) { return new EvaluateException(DebuggerBundle.message("error.inconsistent.debug.info"), null); } - else if(e instanceof InvalidStackFrameException) { + else if (e instanceof InvalidStackFrameException) { return new EvaluateException(DebuggerBundle.message("error.invalid.stackframe"), null); } else { @@ -104,6 +110,7 @@ public abstract class NodeDescriptorImpl implements NodeDescriptor { } } + @Override public void displayAs(NodeDescriptor descriptor) { if (descriptor instanceof NodeDescriptorImpl) { final NodeDescriptorImpl that = (NodeDescriptorImpl)descriptor; @@ -122,6 +129,7 @@ public abstract class NodeDescriptorImpl implements NodeDescriptor { return myEvaluateException; } + @Override public String getLabel() { return myLabel; } @@ -149,6 +157,7 @@ public abstract class NodeDescriptorImpl implements NodeDescriptor { return myChildren; } + @Override public void setAncestor(NodeDescriptor oldDescriptor) { displayAs(oldDescriptor); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java index 41a5384ae19b..8e11e545dcd0 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java @@ -34,6 +34,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.ui.FileColorManager; import com.intellij.util.StringBuilderSpinAllocator; +import com.intellij.util.ui.TextTransferable; +import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.sun.jdi.*; import org.jetbrains.annotations.Nullable; @@ -50,6 +52,7 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac private int myUiIndex; private String myName = null; private Location myLocation; + private final XStackFrame myXStackFrame; private MethodsTracker.MethodOccurrence myMethodOccurrence; private boolean myIsSynthetic; private boolean myIsInLibraryContent; @@ -67,6 +70,7 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac myMethodOccurrence = tracker.getMethodOccurrence(myLocation.method()); myIsSynthetic = DebuggerUtils.isSynthetic(myMethodOccurrence.getMethod()); ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override public void run() { final SourcePosition position = ContextUtil.getSourcePosition(StackFrameDescriptorImpl.this); final PsiFile file = position != null? position.getFile() : null; @@ -83,7 +87,7 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac } }); } - catch(InternalException e) { + catch (InternalException e) { LOG.info(e); myLocation = null; myMethodOccurrence = tracker.getMethodOccurrence(null); @@ -97,16 +101,20 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac myIsSynthetic = false; myIsInLibraryContent = false; } + + myXStackFrame = myLocation == null ? null : getDebugProcess().getPositionManager().createStackFrame(myLocation); } public int getUiIndex() { return myUiIndex; } + @Override public StackFrameProxyImpl getFrameProxy() { return myFrame; } + @Override public DebugProcess getDebugProcess() { return myFrame.getVirtualMachine().getDebugProcess(); } @@ -140,12 +148,21 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac return null; } + @Override public String getName() { return myName; } + @Override protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener descriptorLabelListener) throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); + + if (myXStackFrame != null) { + TextTransferable.ColoredStringBuilder builder = new TextTransferable.ColoredStringBuilder(); + myXStackFrame.customizePresentation(builder); + return builder.getBuilder().toString(); + } + if (myLocation == null) { return ""; } @@ -159,7 +176,7 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac label.append("()"); } if (settings.SHOW_LINE_NUMBER) { - String lineNumber = null; + String lineNumber; try { lineNumber = Integer.toString(myLocation.lineNumber()); } @@ -172,7 +189,7 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac } } if (settings.SHOW_CLASS_NAME) { - String name = null; + String name; try { ReferenceType refType = myLocation.declaringType(); name = refType != null ? refType.name() : null; @@ -206,7 +223,7 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac label.append(", "); label.append(sourceName); } - catch (AbsentInformationException exception) { + catch (AbsentInformationException ignored) { } } return label.toString(); @@ -220,10 +237,12 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac return getFrameProxy().equals(d.getFrameProxy()); } + @Override public boolean isExpandable() { return true; } + @Override public final void setContext(EvaluationContextImpl context) { myIcon = calcIcon(); } @@ -246,7 +265,7 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac return AllIcons.Debugger.Db_obsolete; } } - catch (EvaluateException e) { + catch (EvaluateException ignored) { } return AllIcons.Debugger.StackFrame; } diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java b/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java index 21cdb36a3a4e..5df69039a726 100644 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java @@ -1,16 +1,28 @@ package org.jetbrains.java.debugger; +import com.intellij.debugger.engine.evaluation.CodeFragmentKind; +import com.intellij.debugger.engine.evaluation.TextWithImports; +import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; +import com.intellij.debugger.ui.DebuggerExpressionComboBox; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.JavaCodeFragmentFactory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProviderBase; +import com.intellij.xdebugger.impl.breakpoints.ui.XDebuggerComboBoxProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class JavaDebuggerEditorsProvider extends XDebuggerEditorsProviderBase { +import javax.swing.*; + +public class JavaDebuggerEditorsProvider extends XDebuggerEditorsProviderBase implements XDebuggerComboBoxProvider { @NotNull @Override public FileType getFileType() { @@ -21,4 +33,77 @@ public class JavaDebuggerEditorsProvider extends XDebuggerEditorsProviderBase { protected PsiFile createExpressionCodeFragment(@NotNull Project project, @NotNull String text, @Nullable PsiElement context, boolean isPhysical) { return JavaCodeFragmentFactory.getInstance(project).createExpressionCodeFragment(text, context, null, isPhysical); } + + @Override + public XBreakpointCustomPropertiesPanel<XBreakpoint<?>> createConditionComboBoxPanel(Project project, + XDebuggerEditorsProvider debuggerEditorsProvider, + String historyId, + XSourcePosition sourcePosition) { + return new ExpressionComboBoxPanel(project, historyId, sourcePosition) { + @Override + public void saveTo(@NotNull XBreakpoint<?> breakpoint) { + TextWithImports text = myComboBox.getText(); + final String condition = !text.getText().isEmpty() ? text.toExternalForm() : null; + breakpoint.setCondition(condition); + if (condition != null) { + myComboBox.addRecent(text); + } + } + + @Override + public void loadFrom(@NotNull XBreakpoint<?> breakpoint) { + myComboBox.setText(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, StringUtil.notNullize(breakpoint.getCondition()))); + } + }; + } + + @Override + public XBreakpointCustomPropertiesPanel<XBreakpoint<?>> createLogExpressionComboBoxPanel(Project project, + XDebuggerEditorsProvider debuggerEditorsProvider, + String historyId, + XSourcePosition sourcePosition) { + return new ExpressionComboBoxPanel(project, historyId, sourcePosition) { + @Override + public void saveTo(@NotNull XBreakpoint<?> breakpoint) { + TextWithImports text = myComboBox.getText(); + breakpoint.setLogExpression(myComboBox.isEnabled() && !text.getText().isEmpty() ? text.toExternalForm() : null); + if (text != null) { + myComboBox.addRecent(text); + } + } + + @Override + public void loadFrom(@NotNull XBreakpoint<?> breakpoint) { + myComboBox.setText(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, StringUtil.notNullize(breakpoint.getLogExpression()))); + } + }; + } + + private abstract class ExpressionComboBoxPanel extends XBreakpointCustomPropertiesPanel<XBreakpoint<?>> { + protected final DebuggerExpressionComboBox myComboBox; + + private ExpressionComboBoxPanel(Project project, + String historyId, + XSourcePosition sourcePosition) { + myComboBox = new DebuggerExpressionComboBox(project, historyId); + if (sourcePosition != null) { + PsiElement element = getContextElement(sourcePosition.getFile(), sourcePosition.getOffset(), project); + myComboBox.setContext(element); + } + else { + myComboBox.setContext(null); + } + } + + @NotNull + @Override + public JComponent getComponent() { + return myComboBox; + } + + @Override + public void dispose() { + myComboBox.dispose(); + } + } }
\ No newline at end of file diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointAdapter.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointAdapter.java deleted file mode 100644 index a6705848a44d..000000000000 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointAdapter.java +++ /dev/null @@ -1,157 +0,0 @@ -package org.jetbrains.java.debugger.breakpoints; - -import com.intellij.debugger.engine.evaluation.CodeFragmentKind; -import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; -import com.intellij.debugger.engine.requests.RequestManagerImpl; -import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.debugger.ui.breakpoints.LineBreakpoint; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.markup.RangeHighlighter; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.xdebugger.breakpoints.XBreakpointProperties; -import com.intellij.xdebugger.breakpoints.XLineBreakpoint; -import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; - -public class JavaBreakpointAdapter extends JavaBreakpointAdapterBase { - private static final Key<LineBreakpoint> OLD_JAVA_BREAKPOINT_KEY = Key.create("oldJavaBreakpoint"); - - public JavaBreakpointAdapter(Project project) { - super(project); - } - - @Override - protected void configureCreatedBreakpoint(LineBreakpoint oldBreakpoint, XLineBreakpoint<XBreakpointProperties> breakpoint) { - oldBreakpoint.SUSPEND_POLICY = transformSuspendPolicy(breakpoint); - applyCondition(oldBreakpoint, breakpoint); - applyFilters(oldBreakpoint, breakpoint); - } - - private boolean applyFilters(LineBreakpoint oldBreakpoint, XLineBreakpoint<XBreakpointProperties> breakpoint) { - boolean changed = false; - JavaBreakpointProperties properties = (JavaBreakpointProperties)breakpoint.getProperties(); - - changed |= oldBreakpoint.COUNT_FILTER_ENABLED != properties.COUNT_FILTER_ENABLED; - oldBreakpoint.COUNT_FILTER_ENABLED = properties.COUNT_FILTER_ENABLED; - - changed |= oldBreakpoint.COUNT_FILTER != properties.COUNT_FILTER; - oldBreakpoint.COUNT_FILTER = properties.COUNT_FILTER; - - changed |= oldBreakpoint.CLASS_FILTERS_ENABLED != properties.CLASS_FILTERS_ENABLED; - oldBreakpoint.CLASS_FILTERS_ENABLED = properties.CLASS_FILTERS_ENABLED; - - changed |= !Arrays.equals(oldBreakpoint.getClassFilters(), properties.getClassFilters()); - oldBreakpoint.setClassFilters(properties.getClassFilters()); - - changed |= !Arrays.equals(oldBreakpoint.getClassExclusionFilters(), properties.getClassExclusionFilters()); - oldBreakpoint.setClassExclusionFilters(properties.getClassExclusionFilters()); - - changed |= oldBreakpoint.INSTANCE_FILTERS_ENABLED != properties.INSTANCE_FILTERS_ENABLED; - oldBreakpoint.INSTANCE_FILTERS_ENABLED = properties.INSTANCE_FILTERS_ENABLED; - - changed |= !Arrays.equals(oldBreakpoint.getInstanceFilters(), properties.getInstanceFilters()); - oldBreakpoint.setInstanceFilters(properties.getInstanceFilters()); - - return changed; - } - - private static void applyCondition(LineBreakpoint oldBreakpoint, XLineBreakpoint<XBreakpointProperties> breakpoint) { - if (breakpoint.getCondition() != null) { - oldBreakpoint.CONDITION_ENABLED = true; - oldBreakpoint.setCondition(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, breakpoint.getCondition())); - } - else { - oldBreakpoint.CONDITION_ENABLED = false; - if (!StringUtil.isEmptyOrSpaces(oldBreakpoint.getCondition().getText())) { - oldBreakpoint.setCondition(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "")); - } - } - } - - @Override - protected void updateBreakpoint(LineBreakpoint jBreakpoint, XLineBreakpoint<XBreakpointProperties> breakpoint) { - boolean changed = false; - if (jBreakpoint.ENABLED != breakpoint.isEnabled()) { - jBreakpoint.ENABLED = breakpoint.isEnabled(); - changed = true; - } - - String suspendPolicy = transformSuspendPolicy(breakpoint); - if (jBreakpoint.SUSPEND_POLICY != suspendPolicy) { - jBreakpoint.SUSPEND_POLICY = suspendPolicy; - changed = true; - } - - if (StringUtil.compare(breakpoint.getCondition(), jBreakpoint.getCondition().getText(), false) != 0) { - applyCondition(jBreakpoint, breakpoint); - changed = true; - } - - if (applyFilters(jBreakpoint, breakpoint)) { - changed = true; - } - - if (jBreakpoint.getSourcePosition().getLine() != breakpoint.getLine()) { - jBreakpoint.reload(); - changed = true; - } - - if (changed) { - RequestManagerImpl.updateRequests(jBreakpoint); - jBreakpoint.updateUI(); - } - } - - @Override - protected LineBreakpoint findBreakpoint(XLineBreakpoint<XBreakpointProperties> breakpoint) { - return OLD_JAVA_BREAKPOINT_KEY.get(breakpoint); - } - - public LineBreakpoint getOrCreate(XLineBreakpoint<XBreakpointProperties> breakpoint) { - LineBreakpoint oldBreakpoint = findBreakpoint(breakpoint); - if (oldBreakpoint == null) { - oldBreakpoint = createBreakpoint(breakpoint); - OLD_JAVA_BREAKPOINT_KEY.set(breakpoint, oldBreakpoint); - } - return oldBreakpoint; - } - - @Override - public void breakpointRemoved(@NotNull XLineBreakpoint<XBreakpointProperties> breakpoint) { - LineBreakpoint jBreakpoint = findBreakpoint(breakpoint); - if (jBreakpoint != null) { - jBreakpoint.delete(); - } - } - - @Override - protected LineBreakpoint doCreateInstance(Project project, Document document, XLineBreakpoint<XBreakpointProperties> breakpoint) { - LineBreakpoint lineBreakpoint = new LineBreakpoint(project, ((XLineBreakpointImpl)breakpoint).getHighlighter()) { - @Override - protected void setEditorFilter(RangeHighlighter highlighter) { - } - }; - - lineBreakpoint.setVisible(false); - lineBreakpoint.init(); - return lineBreakpoint; - } - - private static String transformSuspendPolicy(XLineBreakpoint<XBreakpointProperties> breakpoint) { - switch (breakpoint.getSuspendPolicy()) { - case ALL: - return DebuggerSettings.SUSPEND_ALL; - case THREAD: - return DebuggerSettings.SUSPEND_THREAD; - case NONE: - return DebuggerSettings.SUSPEND_NONE; - - default: - throw new IllegalArgumentException("unknown suspend policy"); - } - } -} diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointAdapterBase.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointAdapterBase.java index 6b249356d340..686de9aad6eb 100644 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointAdapterBase.java +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointAdapterBase.java @@ -56,11 +56,11 @@ public abstract class JavaBreakpointAdapterBase extends XBreakpointAdapter<XLine LineBreakpoint oldBreakpoint = doCreateInstance(project, document, breakpoint); oldBreakpoint.setVisible(false); oldBreakpoint.updateUI(); - oldBreakpoint.ENABLED = breakpoint.isEnabled(); + oldBreakpoint.setEnabled(breakpoint.isEnabled()); return oldBreakpoint; } - protected LineBreakpoint doCreateInstance(Project project, Document document, XLineBreakpoint<XBreakpointProperties> breakpoint) { - return LineBreakpoint.create(project, document, breakpoint.getLine()); + protected LineBreakpoint doCreateInstance(Project project, Document document, XLineBreakpoint<XBreakpointProperties> xBreakpoint) { + return LineBreakpoint.create(project, xBreakpoint); } } diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointPropertiesPanel.form b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.form index db560b3feaeb..39507678f8ff 100644 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointPropertiesPanel.form +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.form @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.java.debugger.breakpoints.JavaBreakpointPropertiesPanel"> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.java.debugger.breakpoints.JavaBreakpointFiltersPanel"> <grid id="27dc6" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointPropertiesPanel.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java index e575973ea0ba..2afcf0fd339f 100644 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointPropertiesPanel.java +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java @@ -26,11 +26,11 @@ import com.intellij.ui.FieldPanel; import com.intellij.ui.MultiLineTooltipUI; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.xdebugger.XSourcePosition; -import com.intellij.xdebugger.breakpoints.XBreakpointProperties; -import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; import javax.swing.*; import java.awt.*; @@ -44,7 +44,7 @@ import java.util.List; /** * @author egor */ -public class JavaBreakpointPropertiesPanel extends XBreakpointCustomPropertiesPanel<XLineBreakpoint<XBreakpointProperties>> { +public class JavaBreakpointFiltersPanel<T extends JavaBreakpointProperties, B extends XBreakpoint<T>> extends XBreakpointCustomPropertiesPanel<B> { private JPanel myConditionsPanel; private JPanel myInstanceFiltersPanel; private JCheckBox myInstanceFiltersCheckBox; @@ -66,7 +66,7 @@ public class JavaBreakpointPropertiesPanel extends XBreakpointCustomPropertiesPa private PsiClass myBreakpointPsiClass; - public JavaBreakpointPropertiesPanel(Project project) { + public JavaBreakpointFiltersPanel(Project project) { myProject = project; myInstanceFiltersField = new FieldPanel(new MyTextField(), "", null, new ActionListener() { @@ -135,8 +135,8 @@ public class JavaBreakpointPropertiesPanel extends XBreakpointCustomPropertiesPa } @Override - public boolean isVisibleOnPopup(@NotNull XLineBreakpoint<XBreakpointProperties> breakpoint) { - JavaBreakpointProperties properties = (JavaBreakpointProperties)breakpoint.getProperties(); + public boolean isVisibleOnPopup(@NotNull B breakpoint) { + JavaBreakpointProperties properties = breakpoint.getProperties(); if (properties != null) { return properties.COUNT_FILTER_ENABLED || properties.CLASS_FILTERS_ENABLED || properties.INSTANCE_FILTERS_ENABLED; } @@ -144,8 +144,8 @@ public class JavaBreakpointPropertiesPanel extends XBreakpointCustomPropertiesPa } @Override - public void saveTo(@NotNull XLineBreakpoint<XBreakpointProperties> breakpoint) { - JavaBreakpointProperties properties = (JavaBreakpointProperties)breakpoint.getProperties(); + public void saveTo(@NotNull B breakpoint) { + JavaBreakpointProperties properties = breakpoint.getProperties(); if (properties == null) { return; } @@ -179,8 +179,8 @@ public class JavaBreakpointPropertiesPanel extends XBreakpointCustomPropertiesPa } @Override - public void loadFrom(@NotNull XLineBreakpoint<XBreakpointProperties> breakpoint) { - JavaBreakpointProperties properties = (JavaBreakpointProperties)breakpoint.getProperties(); + public void loadFrom(@NotNull B breakpoint) { + JavaBreakpointProperties properties = breakpoint.getProperties(); if (properties != null) { if (properties.COUNT_FILTER > 0) { myPassCountField.setText(Integer.toString(properties.COUNT_FILTER)); diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointType.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointType.java deleted file mode 100644 index 5e55a49658f8..000000000000 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointType.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.jetbrains.java.debugger.breakpoints; - -import com.intellij.debugger.DebuggerBundle; -import com.intellij.debugger.engine.DebuggerUtils; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.util.SystemProperties; -import com.intellij.xdebugger.XDebuggerUtil; -import com.intellij.xdebugger.breakpoints.XBreakpointProperties; -import com.intellij.xdebugger.breakpoints.XLineBreakpoint; -import com.intellij.xdebugger.breakpoints.XLineBreakpointTypeBase; -import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; -import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.java.debugger.JavaDebuggerEditorsProvider; - -import java.util.List; - -public class JavaBreakpointType extends XLineBreakpointTypeBase { - public JavaBreakpointType() { - super("java", DebuggerBundle.message("java.breakpoint.title"), new JavaDebuggerEditorsProvider()); - } - - @Override - public boolean canPutAt(@NotNull final VirtualFile file, final int line, @NotNull Project project) { - return SystemProperties.getBooleanProperty("java.debugger.xBreakpoint", false) && - doCanPutAt(PsiManager.getInstance(project).findFile(file)); - } - - @Override - public boolean isSuspendThreadSupported() { - return true; - } - - @Override - public List<XBreakpointGroupingRule<XLineBreakpoint<XBreakpointProperties>, ?>> getGroupingRules() { - return XDebuggerUtil.getInstance().getGroupingByFileRuleAsList(); - } - - @Contract("null -> false") - public static boolean doCanPutAt(@Nullable PsiFile psiFile) { - // JSPX supports jvm debugging, but not in XHTML files - if (psiFile == null || psiFile.getVirtualFile().getFileType() == StdFileTypes.XHTML) { - return false; - } - - FileType fileType = psiFile.getFileType(); - return StdFileTypes.CLASS.equals(fileType) || DebuggerUtils.supportsJVMDebugging(fileType) || DebuggerUtils.supportsJVMDebugging(psiFile); - } - - @Nullable - @Override - public XBreakpointProperties createProperties() { - return new JavaBreakpointProperties(); - } - - @Nullable - @Override - public XBreakpointProperties createBreakpointProperties(@NotNull VirtualFile file, int line) { - return new JavaBreakpointProperties(); - } - - @Nullable - @Override - public XBreakpointCustomPropertiesPanel<XLineBreakpoint<XBreakpointProperties>> createCustomRightPropertiesPanel(@NotNull Project project) { - return new JavaBreakpointPropertiesPanel(project); - } - - -}
\ No newline at end of file diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointProperties.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaBreakpointProperties.java index e2f3202a0d46..daab63a93265 100644 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointProperties.java +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaBreakpointProperties.java @@ -13,27 +13,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.java.debugger.breakpoints; +package org.jetbrains.java.debugger.breakpoints.properties; import com.intellij.debugger.InstanceFilter; import com.intellij.ui.classFilter.ClassFilter; +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.OptionTag; +import com.intellij.util.xmlb.annotations.Tag; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; import org.jetbrains.annotations.Nullable; /** * @author egor */ -public class JavaBreakpointProperties extends XBreakpointProperties<JavaBreakpointProperties> { +public class JavaBreakpointProperties<T extends JavaBreakpointProperties> extends XBreakpointProperties<T> { + @OptionTag("count-filter-enabled") public boolean COUNT_FILTER_ENABLED = false; + @OptionTag("count-filter") public int COUNT_FILTER = 0; + @OptionTag("class-filters-enabled") public boolean CLASS_FILTERS_ENABLED = false; private ClassFilter[] myClassFilters; private ClassFilter[] myClassExclusionFilters; + @OptionTag("instance-filters-enabled") public boolean INSTANCE_FILTERS_ENABLED = false; private InstanceFilter[] myInstanceFilters; + @Tag("instance-filters") + @AbstractCollection(surroundWithTag = false) public InstanceFilter[] getInstanceFilters() { return myInstanceFilters != null ? myInstanceFilters : InstanceFilter.EMPTY_ARRAY; } @@ -42,13 +51,15 @@ public class JavaBreakpointProperties extends XBreakpointProperties<JavaBreakpoi myInstanceFilters = instanceFilters; } - protected void addInstanceFilter(long l) { + public void addInstanceFilter(long l) { final InstanceFilter[] filters = new InstanceFilter[myInstanceFilters.length + 1]; System.arraycopy(myInstanceFilters, 0, filters, 0, myInstanceFilters.length); filters[myInstanceFilters.length] = InstanceFilter.create(String.valueOf(l)); myInstanceFilters = filters; } + @Tag("class-filters") + @AbstractCollection(surroundWithTag = false) public final ClassFilter[] getClassFilters() { return myClassFilters != null ? myClassFilters : ClassFilter.EMPTY_ARRAY; } @@ -57,6 +68,8 @@ public class JavaBreakpointProperties extends XBreakpointProperties<JavaBreakpoi myClassFilters = classFilters; } + @Tag("class-exclusion-filters") + @AbstractCollection(surroundWithTag = false) public ClassFilter[] getClassExclusionFilters() { return myClassExclusionFilters != null ? myClassExclusionFilters : ClassFilter.EMPTY_ARRAY; } @@ -67,20 +80,20 @@ public class JavaBreakpointProperties extends XBreakpointProperties<JavaBreakpoi @Nullable @Override - public JavaBreakpointProperties getState() { - return this; + public T getState() { + return (T)this; } @Override - public void loadState(JavaBreakpointProperties state) { + public void loadState(T state) { COUNT_FILTER_ENABLED = state.COUNT_FILTER_ENABLED; COUNT_FILTER = state.COUNT_FILTER; CLASS_FILTERS_ENABLED = state.CLASS_FILTERS_ENABLED; - myClassFilters = state.myClassFilters; - myClassExclusionFilters = state.myClassExclusionFilters; + myClassFilters = state.getClassFilters(); + myClassExclusionFilters = state.getClassExclusionFilters(); INSTANCE_FILTERS_ENABLED = state.INSTANCE_FILTERS_ENABLED; - myInstanceFilters = state.myInstanceFilters; + myInstanceFilters = state.getInstanceFilters(); } } diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaExceptionBreakpointProperties.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaExceptionBreakpointProperties.java new file mode 100644 index 000000000000..e3b893e926ee --- /dev/null +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaExceptionBreakpointProperties.java @@ -0,0 +1,57 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.debugger.breakpoints.properties; + +import com.intellij.util.xmlb.annotations.Attribute; +import org.jetbrains.annotations.Nullable; + +/** + * @author egor + */ +public class JavaExceptionBreakpointProperties extends JavaBreakpointProperties<JavaExceptionBreakpointProperties> { + public boolean NOTIFY_CAUGHT = true; + public boolean NOTIFY_UNCAUGHT = true; + + @Attribute("class") + public String myQualifiedName; + + @Attribute("package") + public String myPackageName; + + public JavaExceptionBreakpointProperties(String qualifiedName, String packageName) { + myQualifiedName = qualifiedName; + myPackageName = packageName; + } + + public JavaExceptionBreakpointProperties() { + } + + @Nullable + @Override + public JavaExceptionBreakpointProperties getState() { + return this; + } + + @Override + public void loadState(JavaExceptionBreakpointProperties state) { + super.loadState(state); + + NOTIFY_CAUGHT = state.NOTIFY_CAUGHT; + NOTIFY_UNCAUGHT = state.NOTIFY_UNCAUGHT; + myQualifiedName = state.myQualifiedName; + myPackageName = state.myPackageName; + } +} diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaFieldBreakpointProperties.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaFieldBreakpointProperties.java new file mode 100644 index 000000000000..13b760e81428 --- /dev/null +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaFieldBreakpointProperties.java @@ -0,0 +1,57 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.debugger.breakpoints.properties; + +import com.intellij.util.xmlb.annotations.Attribute; +import org.jetbrains.annotations.Nullable; + +/** + * @author egor + */ +public class JavaFieldBreakpointProperties extends JavaBreakpointProperties<JavaFieldBreakpointProperties> { + public boolean WATCH_MODIFICATION = true; + public boolean WATCH_ACCESS = false; + + @Attribute("field") + public String myFieldName; + + @Attribute("class") + public String myClassName; + + public JavaFieldBreakpointProperties(String fieldName, String className) { + myFieldName = fieldName; + myClassName = className; + } + + public JavaFieldBreakpointProperties() { + } + + @Nullable + @Override + public JavaFieldBreakpointProperties getState() { + return this; + } + + @Override + public void loadState(JavaFieldBreakpointProperties state) { + super.loadState(state); + + WATCH_MODIFICATION = state.WATCH_MODIFICATION; + WATCH_ACCESS = state.WATCH_ACCESS; + myFieldName = state.myFieldName; + myClassName = state.myClassName; + } +} diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaLineBreakpointProperties.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaLineBreakpointProperties.java new file mode 100644 index 000000000000..9a892346ac04 --- /dev/null +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaLineBreakpointProperties.java @@ -0,0 +1,22 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.debugger.breakpoints.properties; + +/** + * @author egor + */ +public class JavaLineBreakpointProperties extends JavaBreakpointProperties<JavaLineBreakpointProperties> { +} diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaMethodBreakpointProperties.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaMethodBreakpointProperties.java new file mode 100644 index 000000000000..9392b565645b --- /dev/null +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/properties/JavaMethodBreakpointProperties.java @@ -0,0 +1,58 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.debugger.breakpoints.properties; + +import com.intellij.util.xmlb.annotations.Attribute; +import org.jetbrains.annotations.Nullable; + +/** + * @author egor + */ +public class JavaMethodBreakpointProperties extends JavaBreakpointProperties<JavaMethodBreakpointProperties> { + @Attribute("class") + public String myClassPattern; + + @Attribute("method") + public String myMethodName; + + public boolean WATCH_ENTRY = true; + public boolean WATCH_EXIT = true; + + public JavaMethodBreakpointProperties(String classPattern, String methodName) { + myClassPattern = classPattern; + myMethodName = methodName; + } + + public JavaMethodBreakpointProperties() { + } + + @Nullable + @Override + public JavaMethodBreakpointProperties getState() { + return this; + } + + @Override + public void loadState(JavaMethodBreakpointProperties state) { + super.loadState(state); + + myClassPattern = state.myClassPattern; + myMethodName = state.myMethodName; + + WATCH_ENTRY = state.WATCH_ENTRY; + WATCH_EXIT = state.WATCH_EXIT; + } +} diff --git a/java/debugger/openapi/src/com/intellij/debugger/PositionManagerEx.java b/java/debugger/openapi/src/com/intellij/debugger/PositionManagerEx.java new file mode 100644 index 000000000000..c1faee1f763f --- /dev/null +++ b/java/debugger/openapi/src/com/intellij/debugger/PositionManagerEx.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2013 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.debugger; + +import com.intellij.xdebugger.frame.XStackFrame; +import com.sun.jdi.Location; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class PositionManagerEx implements PositionManager { + @Nullable + public abstract XStackFrame createStackFrame(@NotNull Location location); +} diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java index 66fea2d7f38c..43c7fd47f02f 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java @@ -16,6 +16,7 @@ package com.intellij.debugger.engine; import com.intellij.debugger.PositionManager; +import com.intellij.debugger.PositionManagerEx; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.jdi.VirtualMachineProxy; @@ -44,7 +45,7 @@ public interface DebugProcess { RequestManager getRequestsManager(); - PositionManager getPositionManager(); + PositionManagerEx getPositionManager(); VirtualMachineProxy getVirtualMachineProxy(); diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java b/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java index 1697684b9d21..b200e0ef1829 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java @@ -80,6 +80,7 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager { return myStratumId; } + @Override public SourcePosition getSourcePosition(final Location location) throws NoDataException { SourcePosition sourcePosition = null; @@ -110,6 +111,7 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager { return location.lineNumber(myStratumId); } + @Override @NotNull public List<ReferenceType> getAllClasses(SourcePosition classPosition) throws NoDataException { checkSourcePositionFileType(classPosition); @@ -138,6 +140,7 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager { } } + @Override @NotNull public List<Location> locationsOfLine(final ReferenceType type, final SourcePosition position) throws NoDataException { List<Location> locations = locationsOfClassAt(type, position); @@ -149,6 +152,7 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager { checkSourcePositionFileType(position); return ApplicationManager.getApplication().runReadAction(new Computable<List<Location>>() { + @Override public List<Location> compute() { try { final List<String> relativePaths = getRelativeSourePathsByType(type); @@ -165,7 +169,7 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager { } catch(ClassNotPreparedException ignored) { } - catch (InternalError e) { + catch (InternalError ignored) { myDebugProcess.getExecutionResult().getProcessHandler().notifyTextAvailable( DebuggerBundle.message("internal.error.locations.of.line", type.name()), ProcessOutputTypes.SYSTEM); } @@ -176,7 +180,7 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager { // This is needed because some servers (e.g. WebSphere) put not exact file name such as 'A.jsp ' private String getSourceName(final String name, final ReferenceType type) throws AbsentInformationException { for(String sourceNameFromType: type.sourceNames(myStratumId)) { - if (sourceNameFromType.indexOf(name) >= 0) { + if (sourceNameFromType.contains(name)) { return sourceNameFromType; } } @@ -199,11 +203,13 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager { return type.locationsOfLine(myStratumId, fileName, lineNumber); } + @Override public ClassPrepareRequest createPrepareRequest(final ClassPrepareRequestor requestor, final SourcePosition position) throws NoDataException { checkSourcePositionFileType(position); return myDebugProcess.getRequestsManager().createClassPrepareRequest(new ClassPrepareRequestor() { + @Override public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) { onClassPrepare(debuggerProcess, referenceType, position, requestor); } @@ -217,7 +223,7 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager { requestor.processClassPrepare(debuggerProcess, referenceType); } } - catch (NoDataException e) { + catch (NoDataException ignored) { } } diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/StackFrameProxy.java b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/StackFrameProxy.java index 7e0b6ee007f1..511b1af39daf 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/StackFrameProxy.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/StackFrameProxy.java @@ -19,6 +19,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.sun.jdi.ClassLoaderReference; import com.sun.jdi.Location; import com.sun.jdi.StackFrame; +import org.jetbrains.annotations.Nullable; public interface StackFrameProxy extends ObjectReferenceProxy{ StackFrame getStackFrame() throws EvaluateException; @@ -27,6 +28,7 @@ public interface StackFrameProxy extends ObjectReferenceProxy{ VirtualMachineProxy getVirtualMachine(); + @Nullable Location location() throws EvaluateException; ClassLoaderReference getClassLoader() throws EvaluateException; diff --git a/java/idea-ui/src/com/intellij/ide/impl/ProjectStructureSelectInTarget.java b/java/idea-ui/src/com/intellij/ide/impl/ProjectStructureSelectInTarget.java index d282c684e3db..70457eb6bdf3 100644 --- a/java/idea-ui/src/com/intellij/ide/impl/ProjectStructureSelectInTarget.java +++ b/java/idea-ui/src/com/intellij/ide/impl/ProjectStructureSelectInTarget.java @@ -18,6 +18,7 @@ package com.intellij.ide.impl; import com.intellij.facet.*; import com.intellij.ide.*; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.DumbAware; @@ -48,7 +49,8 @@ public class ProjectStructureSelectInTarget extends SelectInTargetBase implement final Object o = ((WrappingVirtualFile)file).getWrappedObject(context.getProject()); return o instanceof Facet; } - return fileIndex.isInContent(file) || fileIndex.isInLibraryClasses(file) || fileIndex.isInLibrarySource(file); + return fileIndex.isInContent(file) || fileIndex.isInLibraryClasses(file) || fileIndex.isInLibrarySource(file) + || StdFileTypes.IDEA_MODULE.equals(file.getFileType()) && findModuleByModuleFile(context.getProject(), file) != null; } @Override @@ -64,8 +66,9 @@ public class ProjectStructureSelectInTarget extends SelectInTargetBase implement module = facet == null? null : facet.getModule(); } else { + Module moduleByIml = file.getFileType().equals(StdFileTypes.IDEA_MODULE) ? findModuleByModuleFile(project, file) : null; final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - module = fileIndex.getModuleForFile(file); + module = moduleByIml != null ? moduleByIml : fileIndex.getModuleForFile(file); facet = fileIndex.isInSourceContent(file) ? null : findFacet(project, file); } if (module != null || facet != null) { @@ -95,6 +98,16 @@ public class ProjectStructureSelectInTarget extends SelectInTargetBase implement } @Nullable + private static Module findModuleByModuleFile(@NotNull Project project, @NotNull VirtualFile file) { + for (Module module : ModuleManager.getInstance(project).getModules()) { + if (file.equals(module.getModuleFile())) { + return module; + } + } + return null; + } + + @Nullable private static Facet findFacet(final @NotNull Project project, final @NotNull VirtualFile file) { for (FacetTypeId id : FacetTypeRegistry.getInstance().getFacetTypeIds()) { if (hasFacetWithRoots(project, id)) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 324a222a018d..72ad0f26efa1 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -406,8 +406,9 @@ public class GenericsHighlightUtil { if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && aClass.isInterface() && method.hasModifierProperty(PsiModifier.DEFAULT)) { HierarchicalMethodSignature sig = method.getHierarchicalMethodSignature(); for (HierarchicalMethodSignature methodSignature : sig.getSuperSignatures()) { - final PsiClass containingClass = methodSignature.getMethod().getContainingClass(); - if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())) { + final PsiMethod objectMethod = methodSignature.getMethod(); + final PsiClass containingClass = objectMethod.getContainingClass(); + if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && objectMethod.hasModifierProperty(PsiModifier.PUBLIC)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .descriptionAndTooltip("Default method '" + sig.getName() + "' overrides a member of 'java.lang.Object'") .range(methodIdentifier) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 4e9d79fecf57..352e74557eed 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -1324,8 +1324,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list, myLanguageLevel,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list)); if (!myHolder.hasErrorResults()) { - for (PsiType type : list.getTypeArguments()) { - myHolder.add(HighlightUtil.checkDiamondFeature(type, list, myLanguageLevel,myFile)); + for (PsiTypeElement typeElement : list.getTypeParameterElements()) { + myHolder.add(HighlightUtil.checkDiamondFeature(typeElement.getType(), list, myLanguageLevel,myFile)); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java index b9c5d21bcd5e..a5104f1deb51 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.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,11 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.intellij.util.ObjectUtils.assertNotNull; + public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement { private final PsiType myType; @@ -75,28 +76,26 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement addTypeCast(project, (PsiExpression)startElement, myType); } - private static void addTypeCast(Project project, PsiExpression originalExpression, PsiType type) throws IncorrectOperationException { + private static void addTypeCast(Project project, PsiExpression originalExpression, PsiType type) { PsiExpression typeCast = createCastExpression(originalExpression, project, type); originalExpression.replace(typeCast); } - static PsiExpression createCastExpression(PsiExpression originalExpression, Project project, PsiType type) throws IncorrectOperationException { + static PsiExpression createCastExpression(PsiExpression originalExpression, Project project, PsiType type) { // remove nested casts - PsiElement element = PsiUtil.deparenthesizeExpression(originalExpression); - if (element == null){ - return null; - } - PsiElementFactory factory = JavaPsiFacade.getInstance(originalExpression.getProject()).getElementFactory(); + PsiElement expression = PsiUtil.deparenthesizeExpression(originalExpression); + if (expression == null) return null; + PsiElementFactory factory = JavaPsiFacade.getInstance(originalExpression.getProject()).getElementFactory(); PsiTypeCastExpression typeCast = (PsiTypeCastExpression)factory.createExpressionFromText("(Type)value", null); + assertNotNull(typeCast.getCastType()).replace(factory.createTypeElement(type)); typeCast = (PsiTypeCastExpression)CodeStyleManager.getInstance(project).reformat(typeCast); - typeCast.getCastType().replace(factory.createTypeElement(type)); - if (element instanceof PsiConditionalExpression) { - // we'd better cast one branch of ternary expression if we could - PsiConditionalExpression expression = (PsiConditionalExpression)element.copy(); - PsiExpression thenE = expression.getThenExpression(); - PsiExpression elseE = expression.getElseExpression(); + if (expression instanceof PsiConditionalExpression) { + // we'd better cast one branch of ternary expression if we can + PsiConditionalExpression conditional = (PsiConditionalExpression)expression.copy(); + PsiExpression thenE = conditional.getThenExpression(); + PsiExpression elseE = conditional.getElseExpression(); PsiType thenType = thenE == null ? null : thenE.getType(); PsiType elseType = elseE == null ? null : elseE.getType(); if (elseType != null && thenType != null) { @@ -104,18 +103,20 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement boolean replaceElse = !TypeConversionUtil.isAssignable(type, elseType); if (replaceThen != replaceElse) { if (replaceThen) { - typeCast.getOperand().replace(thenE); + assertNotNull(typeCast.getOperand()).replace(thenE); thenE.replace(typeCast); } else { - typeCast.getOperand().replace(elseE); + assertNotNull(typeCast.getOperand()).replace(elseE); elseE.replace(typeCast); } - return expression; + return conditional; } } } - typeCast.getOperand().replace(element); + + assertNotNull(typeCast.getOperand()).replace(expression); + return typeCast; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java index 76580adaa5f4..b4a8d5b99d17 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Created by IntelliJ IDEA. - * User: cdr - * Date: Nov 13, 2002 - * Time: 3:26:50 PM - * To change this template use Options | File Templates. - */ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.FileModificationService; @@ -32,6 +24,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -39,11 +32,18 @@ import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.intellij.util.ObjectUtils.assertNotNull; + +/** + * @author cdr + * @since Nov 13, 2002 + */ public class ChangeTypeArgumentsFix implements IntentionAction, HighPriorityAction { + private static final Logger LOG = Logger.getInstance("#" + ChangeTypeArgumentsFix.class.getName()); + private final PsiMethod myTargetMethod; private final PsiClass myPsiClass; private final PsiExpression[] myExpressions; - private static final Logger LOG = Logger.getInstance("#" + ChangeTypeArgumentsFix.class.getName()); private final PsiNewExpression myNewExpression; ChangeTypeArgumentsFix(@NotNull PsiMethod targetMethod, @@ -116,11 +116,12 @@ public class ChangeTypeArgumentsFix implements IntentionAction, HighPriorityActi LOG.assertTrue(reference != null, myNewExpression); final PsiReferenceParameterList parameterList = reference.getParameterList(); LOG.assertTrue(parameterList != null, myNewExpression); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); PsiTypeElement[] elements = parameterList.getTypeParameterElements(); for (int i = elements.length - 1; i >= 0; i--) { - PsiTypeElement typeElement = elements[i]; - final PsiType typeArg = psiSubstitutor.substitute(typeParameters[i]); - typeElement.replace(JavaPsiFacade.getElementFactory(project).createTypeElement(typeArg)); + PsiType typeArg = assertNotNull(psiSubstitutor.substitute(typeParameters[i])); + PsiElement replaced = elements[i].replace(factory.createTypeElement(typeArg)); + JavaCodeStyleManager.getInstance(file.getProject()).shortenClassReferences(replaced); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java index 987f02dc9c39..84f704f64dcd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java @@ -64,15 +64,25 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement { } @Nullable - public static PsiModifierListOwner getContainer(final PsiElement element) { - PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false); - if (listOwner == null) { - final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false); - if (psiIdentifier != null && psiIdentifier.getParent() instanceof PsiModifierListOwner) { - listOwner = (PsiModifierListOwner)psiIdentifier.getParent(); + public static PsiModifierListOwner getContainer(final PsiFile file, int offset) { + PsiReference reference = file.findReferenceAt(offset); + if (reference != null) { + PsiElement target = reference.resolve(); + if (target instanceof PsiMember) { + return (PsiMember)target; } } - return listOwner; + + PsiElement element = file.findElementAt(offset); + + PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false); + if (listOwner != null) return listOwner; + + final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false); + if (psiIdentifier != null && psiIdentifier.getParent() instanceof PsiModifierListOwner) { + return (PsiModifierListOwner)psiIdentifier.getParent(); + } + return null; } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java index 6684613f0ab0..272ce37708ad 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java @@ -41,7 +41,7 @@ public class AddNullableNotNullAnnotationFix extends AddAnnotationPsiFix { if (!super.isAvailable(project, file, startElement, endElement)) { return false; } - PsiModifierListOwner owner = getContainer(startElement); + PsiModifierListOwner owner = getContainer(file, startElement.getTextRange().getStartOffset()); if (owner == null || AnnotationUtil.isAnnotated(owner, getAnnotationsToRemove()[0], false, false)) { return false; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index ed3494096265..b89473e29b83 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -97,8 +98,11 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection final String localName = local.getName(); if (localName != null && helper.resolveReferencedVariable(localName, aClass) != null) return; } - holder.registerProblem(aClass.getBaseClassReference(), "Anonymous #ref #loc can be replaced with lambda", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithLambdaFix()); + final PsiElement lBrace = aClass.getLBrace(); + LOG.assertTrue(lBrace != null); + final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent()); + holder.registerProblem(aClass.getParent(), "Anonymous #ref #loc can be replaced with lambda", + ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithLambdaFix()); } } } @@ -125,8 +129,8 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { final PsiElement element = descriptor.getPsiElement(); - if (element != null) { - final PsiAnonymousClass anonymousClass = PsiTreeUtil.getParentOfType(element, PsiAnonymousClass.class); + if (element instanceof PsiNewExpression) { + final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass(); LOG.assertTrue(anonymousClass != null); ChangeContextUtil.encodeContextInfo(anonymousClass, true); final PsiElement lambdaContext = anonymousClass.getParent().getParent(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java index 6ad6d223b5a0..6eec61428cda 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java @@ -18,10 +18,10 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.RedundantCastUtil; import org.jetbrains.annotations.Nls; @@ -79,8 +79,11 @@ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalI if (parent instanceof PsiNewExpression) { final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)parent).getClassOrAnonymousClassReference(); if (classReference != null) { - holder.registerProblem(classReference, - "Anonymous #ref #loc can be replaced with method reference", new ReplaceWithMethodRefFix()); + final PsiElement lBrace = aClass.getLBrace(); + LOG.assertTrue(lBrace != null); + final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent()); + holder.registerProblem(parent, + "Anonymous #ref #loc can be replaced with method reference", ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithMethodRefFix()); } } } @@ -107,29 +110,31 @@ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalI @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { final PsiElement element = descriptor.getPsiElement(); - final PsiAnonymousClass anonymousClass = PsiTreeUtil.getParentOfType(element, PsiAnonymousClass.class); - if (anonymousClass == null) return; - final PsiMethod[] methods = anonymousClass.getMethods(); - if (methods.length != 1) return; + if (element instanceof PsiNewExpression) { + final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass(); + if (anonymousClass == null) return; + final PsiMethod[] methods = anonymousClass.getMethods(); + if (methods.length != 1) return; - final PsiParameter[] parameters = methods[0].getParameterList().getParameters(); - final PsiCallExpression callExpression = LambdaCanBeMethodReferenceInspection - .canBeMethodReferenceProblem(methods[0].getBody(), parameters, anonymousClass.getBaseClassType()); - if (callExpression == null) return; - final String methodRefText = - LambdaCanBeMethodReferenceInspection.createMethodReferenceText(callExpression, anonymousClass.getBaseClassType(), parameters); + final PsiParameter[] parameters = methods[0].getParameterList().getParameters(); + final PsiCallExpression callExpression = LambdaCanBeMethodReferenceInspection + .canBeMethodReferenceProblem(methods[0].getBody(), parameters, anonymousClass.getBaseClassType()); + if (callExpression == null) return; + final String methodRefText = + LambdaCanBeMethodReferenceInspection.createMethodReferenceText(callExpression, anonymousClass.getBaseClassType(), parameters); - if (methodRefText != null) { - final String canonicalText = anonymousClass.getBaseClassType().getCanonicalText(); - final PsiExpression psiExpression = JavaPsiFacade.getElementFactory(project).createExpressionFromText("(" + canonicalText + ")" + methodRefText, anonymousClass); - - PsiElement castExpr = anonymousClass.getParent().replace(psiExpression); - if (RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)castExpr)) { - final PsiExpression operand = ((PsiTypeCastExpression)castExpr).getOperand(); - LOG.assertTrue(operand != null); - castExpr = castExpr.replace(operand); + if (methodRefText != null) { + final String canonicalText = anonymousClass.getBaseClassType().getCanonicalText(); + final PsiExpression psiExpression = JavaPsiFacade.getElementFactory(project).createExpressionFromText("(" + canonicalText + ")" + methodRefText, anonymousClass); + + PsiElement castExpr = anonymousClass.getParent().replace(psiExpression); + if (RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)castExpr)) { + final PsiExpression operand = ((PsiTypeCastExpression)castExpr).getOperand(); + LOG.assertTrue(operand != null); + castExpr = castExpr.replace(operand); + } + JavaCodeStyleManager.getInstance(project).shortenClassReferences(castExpr); } - JavaCodeStyleManager.getInstance(project).shortenClassReferences(castExpr); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java index 8a8a6db0752e..9bc2a6ecacc2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java @@ -88,27 +88,7 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp protected static PsiCallExpression canBeMethodReferenceProblem(@Nullable final PsiElement body, final PsiParameter[] parameters, PsiType functionalInterfaceType) { - PsiCallExpression methodCall = null; - if (body instanceof PsiCallExpression) { - methodCall = (PsiCallExpression)body; - } - else if (body instanceof PsiCodeBlock) { - final PsiStatement[] statements = ((PsiCodeBlock)body).getStatements(); - if (statements.length == 1) { - if (statements[0] instanceof PsiReturnStatement) { - final PsiExpression returnValue = ((PsiReturnStatement)statements[0]).getReturnValue(); - if (returnValue instanceof PsiCallExpression) { - methodCall = (PsiCallExpression)returnValue; - } - } - else if (statements[0] instanceof PsiExpressionStatement) { - final PsiExpression expr = ((PsiExpressionStatement)statements[0]).getExpression(); - if (expr instanceof PsiCallExpression) { - methodCall = (PsiCallExpression)expr; - } - } - } - } + PsiCallExpression methodCall = extractMethodCallFromBlock(body); if (methodCall != null) { final PsiExpressionList argumentList = methodCall.getArgumentList(); @@ -218,6 +198,40 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp return null; } + public static PsiCallExpression extractMethodCallFromBlock(PsiElement body) { + PsiCallExpression methodCall = null; + if (body instanceof PsiCallExpression) { + methodCall = (PsiCallExpression)body; + } + else if (body instanceof PsiCodeBlock) { + final PsiStatement[] statements = ((PsiCodeBlock)body).getStatements(); + if (statements.length == 1) { + if (statements[0] instanceof PsiReturnStatement) { + final PsiExpression returnValue = ((PsiReturnStatement)statements[0]).getReturnValue(); + if (returnValue instanceof PsiCallExpression) { + methodCall = (PsiCallExpression)returnValue; + } + } + else if (statements[0] instanceof PsiExpressionStatement) { + final PsiExpression expr = ((PsiExpressionStatement)statements[0]).getExpression(); + if (expr instanceof PsiCallExpression) { + methodCall = (PsiCallExpression)expr; + } + } + } + } + else if (body instanceof PsiBlockStatement) { + return extractMethodCallFromBlock(((PsiBlockStatement)body).getCodeBlock()); + } + else if (body instanceof PsiExpressionStatement) { + final PsiExpression expression = ((PsiExpressionStatement)body).getExpression(); + if (expression instanceof PsiCallExpression) { + methodCall = (PsiCallExpression)expression; + } + } + return methodCall; + } + @Nullable private static PsiMethod ensureNonAmbiguousMethod(PsiParameter[] parameters, @NotNull PsiMethod psiMethod) { String methodName = psiMethod.getName(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java index 8101d16f5a1e..919fb4ea28db 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java @@ -21,7 +21,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.controlFlow.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -106,9 +108,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } }); - if (effectivelyFinal[0] && !isTrivial(body, statement.getIterationParameter(), iteratedValueType)) { - holder.registerProblem(iteratedValue, "Can be replaced with foreach call", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithForeachCallFix()); + if (effectivelyFinal[0]) { + if (isCollectCall(body)) { + holder.registerProblem(iteratedValue, "Can be replaced with collect call", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithCollectCallFix()); + } else if (!isTrivial(body, statement.getIterationParameter(), iteratedValueType)) { + holder.registerProblem(iteratedValue, "Can be replaced with foreach call", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithForeachCallFix()); + } } } } @@ -121,10 +128,46 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo }; } + private static boolean isCollectCall(PsiStatement body) { + final PsiMethodCallExpression methodCallExpression = extractAddCall(body); + if (methodCallExpression != null) { + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); + PsiClass qualifierClass = null; + if (qualifierExpression instanceof PsiReferenceExpression) { + qualifierClass = PsiUtil.resolveClassInType(qualifierExpression.getType()); + } else if (qualifierExpression == null) { + final PsiClass enclosingClass = PsiTreeUtil.getParentOfType(body, PsiClass.class); + if (PsiUtil.getEnclosingStaticElement(body, enclosingClass) == null) { + qualifierClass = enclosingClass; + } + } + + if (qualifierClass != null && + InheritanceUtil.isInheritor(qualifierClass, false, CommonClassNames.JAVA_UTIL_COLLECTION)) { + + final PsiElement resolve = methodExpression.resolve(); + if (resolve instanceof PsiMethod && + "add".equals(((PsiMethod)resolve).getName()) && + ((PsiMethod)resolve).getParameterList().getParametersCount() == 1) { + final PsiExpression[] args = methodCallExpression.getArgumentList().getExpressions(); + if (args.length == 1) { + if (args[0] instanceof PsiCallExpression) { + final PsiMethod method = ((PsiCallExpression)args[0]).resolveMethod(); + return method != null && !method.hasTypeParameters(); + } + return true; + } + } + } + } + return false; + } + private static boolean isTrivial(PsiStatement body, PsiParameter parameter, PsiType iteratedValueType) { final PsiIfStatement ifStatement = extractIfStatement(body); //stream - if (ifStatement != null && ifStatement.getElseBranch() == null && ifStatement.getThenBranch() != null && + if (ifStatement != null && InheritanceUtil.isInheritor(iteratedValueType, CommonClassNames.JAVA_UTIL_COLLECTION)) { return false; } @@ -157,11 +200,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo String foreEachText = body.getText(); String iterated = iteratedValue.getText(); - if (ifStmt != null && ifStmt.getElseBranch() == null) { + if (ifStmt != null) { final PsiExpression condition = ifStmt.getCondition(); if (condition != null) { final PsiStatement thenBranch = ifStmt.getThenBranch(); - if (thenBranch != null && InheritanceUtil.isInheritor(iteratedValue.getType(), CommonClassNames.JAVA_UTIL_COLLECTION)) { + LOG.assertTrue(thenBranch != null); + if (InheritanceUtil.isInheritor(iteratedValue.getType(), CommonClassNames.JAVA_UTIL_COLLECTION)) { body = thenBranch; foreEachText = thenBranch.getText(); iterated += ".stream().filter(" + parameter.getName() + " -> " + condition.getText() +")"; @@ -170,8 +214,16 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } final PsiParameter[] parameters = {parameter}; - final PsiCallExpression expression = LambdaCanBeMethodReferenceInspection.canBeMethodReferenceProblem(body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : body, parameters, null); - final String methodReferenceText = LambdaCanBeMethodReferenceInspection.createMethodReferenceText(expression, null, parameters); + String methodReferenceText = null; + final PsiCallExpression callExpression = LambdaCanBeMethodReferenceInspection.extractMethodCallFromBlock(body); + if (callExpression != null) { + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final PsiClass consumerClass = psiFacade.findClass("java.util.function.Consumer", GlobalSearchScope.allScope(project)); + final PsiClassType functionalType = consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, callExpression.getType()) : null; + + final PsiCallExpression toConvertCall = LambdaCanBeMethodReferenceInspection.canBeMethodReferenceProblem(body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : body, parameters, functionalType); + methodReferenceText = LambdaCanBeMethodReferenceInspection.createMethodReferenceText(toConvertCall, functionalType, parameters); + } final String lambdaText = parameter.getName() + " -> " + foreEachText; final String codeBlock8 = methodReferenceText != null ? methodReferenceText : lambdaText; PsiExpressionStatement callStatement = (PsiExpressionStatement)JavaPsiFacade.getElementFactory(project).createStatementFromText(iterated + ".forEach(" + codeBlock8 + ");", foreachStatement); @@ -191,6 +243,98 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } } + private static class ReplaceWithCollectCallFix implements LocalQuickFix { + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @NotNull + @Override + public String getFamilyName() { + return "Replace with collect"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiForeachStatement foreachStatement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiForeachStatement.class); + if (foreachStatement != null) { + PsiStatement body = foreachStatement.getBody(); + final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); + if (body != null && iteratedValue != null) { + final PsiParameter parameter = foreachStatement.getIterationParameter(); + + final PsiIfStatement ifStatement = extractIfStatement(body); + final PsiMethodCallExpression methodCallExpression = extractAddCall(body); + String iteration = iteratedValue.getText() + ".stream()"; + if (ifStatement != null) { + final PsiExpression condition = ifStatement.getCondition(); + if (condition != null) { + iteration += ".filter(" + parameter.getName() + " -> " + condition.getText() +")"; + } + } + iteration +=".map("; + + final PsiExpression mapperCall = methodCallExpression.getArgumentList().getExpressions()[0]; + + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final PsiClass functionClass = psiFacade.findClass("java.util.function.Function", GlobalSearchScope.allScope(project)); + final PsiClassType functionalInterfaceType = functionClass != null ? psiFacade.getElementFactory().createType(functionClass, parameter.getType(), mapperCall.getType()) : null; + final PsiCallExpression toConvertCall = LambdaCanBeMethodReferenceInspection.canBeMethodReferenceProblem(mapperCall, + new PsiParameter[]{ + parameter}, + functionalInterfaceType); + final String methodReferenceText = LambdaCanBeMethodReferenceInspection.createMethodReferenceText(toConvertCall, functionalInterfaceType, new PsiParameter[]{parameter}); + if (methodReferenceText != null) { + iteration += methodReferenceText; + } else { + iteration += parameter.getName() + " -> " + mapperCall.getText(); + } + iteration += ").collect(java.util.stream.Collectors."; + + String variableName = null; + PsiExpression initializer = null; + final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); + if (qualifierExpression instanceof PsiReferenceExpression) { + final PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); + if (resolve instanceof PsiVariable) { + if (resolve instanceof PsiLocalVariable && foreachStatement.equals(PsiTreeUtil.skipSiblingsForward(resolve.getParent(), PsiWhiteSpace.class))) { + initializer = ((PsiVariable)resolve).getInitializer(); + } + variableName = ((PsiVariable)resolve).getName() + "."; + } + } else if (qualifierExpression == null) { + variableName = ""; + } + + PsiElement result = null; + if (initializer != null) { + final PsiType initializerType = initializer.getType(); + final PsiClassType rawType = initializerType instanceof PsiClassType ? ((PsiClassType)initializerType).rawType() : null; + if (rawType != null && rawType.equalsToText(CommonClassNames.JAVA_UTIL_ARRAY_LIST)) { + iteration += "toList()"; + } else if (rawType != null && rawType.equalsToText(CommonClassNames.JAVA_UTIL_HASH_SET)) { + iteration += "toSet()"; + } else { + iteration += "toCollection(() -> " + initializer.getText() +")"; + } + iteration += ")"; + result = initializer.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText(iteration, foreachStatement)); + foreachStatement.delete(); + } else if (variableName != null){ + iteration += "toList())"; + result = foreachStatement.replace(JavaPsiFacade.getElementFactory(project).createStatementFromText(variableName + "addAll(" + iteration +");", foreachStatement)); + } + + if (result != null) { + result = JavaCodeStyleManager.getInstance(project).shortenClassReferences(result); + } + } + } + } + } + public static PsiIfStatement extractIfStatement(PsiStatement body) { PsiIfStatement ifStmt = null; if (body instanceof PsiIfStatement) { @@ -201,6 +345,34 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo ifStmt = (PsiIfStatement)statements[0]; } } - return ifStmt; + if (ifStmt != null && ifStmt.getElseBranch() == null && ifStmt.getThenBranch() != null) { + return ifStmt; + } + return null; + } + + private static PsiMethodCallExpression extractAddCall(PsiStatement body) { + final PsiIfStatement ifStatement = extractIfStatement(body); + if (ifStatement != null) { + return extractAddCall(ifStatement.getThenBranch()); + } + PsiExpressionStatement stmt = null; + if (body instanceof PsiBlockStatement) { + final PsiStatement[] statements = ((PsiBlockStatement)body).getCodeBlock().getStatements(); + if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement) { + stmt = (PsiExpressionStatement)statements[0]; + } + } + else if (body instanceof PsiExpressionStatement) { + stmt = (PsiExpressionStatement)body; + } + + if (stmt != null) { + final PsiExpression expression = stmt.getExpression(); + if (expression instanceof PsiMethodCallExpression) { + return (PsiMethodCallExpression)expression; + } + } + return null; } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index cc1b2ae059cd..2e15ac48f7f3 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -506,12 +506,16 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message("dataflow.message.return.null.from.notnullable", presentableNullable) : InspectionsBundle.message("dataflow.message.return.nullable.from.notnullable", presentableNullable); - holder.registerProblem(expr, text, new AnnotateMethodFix(defaultNullable, ArrayUtil.toStringArray(manager.getNotNulls())){ - @Override - public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) { - return 1; - } - }); + final LocalQuickFix[] fixes = + PsiTreeUtil.skipParentsOfType(expr, PsiCodeBlock.class, PsiReturnStatement.class) instanceof PsiLambdaExpression + ? LocalQuickFix.EMPTY_ARRAY + : new LocalQuickFix[]{ new AnnotateMethodFix(defaultNullable, ArrayUtil.toStringArray(manager.getNotNulls())) { + @Override + public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) { + return 1; + } + }}; + holder.registerProblem(expr, text, fixes); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java index b647e7d1b37f..f8c395ce17fd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java @@ -81,6 +81,13 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware { } } + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(element); + if (interfaceMethod != null) { + final Icon icon = AllIcons.Gutter.ImplementingMethod; + final MarkerType type = MarkerType.OVERRIDING_METHOD; + return new ArrowUpLineMarkerInfo(element, icon, type); + } + if (myDaemonSettings.SHOW_METHOD_SEPARATORS && element.getFirstChild() == null) { PsiElement element1 = element; boolean isMember = false; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java index 12b1788dcea7..72e8eca35fa6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java @@ -53,27 +53,27 @@ public class MarkerType { public static final MarkerType OVERRIDING_METHOD = new MarkerType(new NullableFunction<PsiElement, String>() { @Override public String fun(PsiElement element) { - PsiElement parent = element.getParent(); + PsiElement parent = getParentMethod(element); if (!(parent instanceof PsiMethod)) return null; PsiMethod method = (PsiMethod)parent; - return calculateOverridingMethodTooltip(method); + return calculateOverridingMethodTooltip(method, method != element.getParent()); } }, new LineMarkerNavigator(){ @Override public void browse(MouseEvent e, PsiElement element) { - PsiElement parent = element.getParent(); + PsiElement parent = getParentMethod(element); if (!(parent instanceof PsiMethod)) return; PsiMethod method = (PsiMethod)parent; - navigateToOverridingMethod(e, method); + navigateToOverridingMethod(e, method, method != element.getParent()); } }); @Nullable - public static String calculateOverridingMethodTooltip(PsiMethod method) { - PsiMethod[] superMethods = method.findSuperMethods(false); - if (superMethods.length == 0) return null; + public static String calculateOverridingMethodTooltip(PsiMethod method, boolean acceptSelf) { + PsiMethod[] superMethods = composeSuperMethods(method, acceptSelf); + if (superMethods == null) return null; PsiMethod superMethod = superMethods[0]; boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); @@ -90,9 +90,9 @@ public class MarkerType { return GutterIconTooltipHelper.composeText(superMethods, "", DaemonBundle.message(key)); } - public static void navigateToOverridingMethod(MouseEvent e, PsiMethod method) { - PsiMethod[] superMethods = method.findSuperMethods(false); - if (superMethods.length == 0) return; + public static void navigateToOverridingMethod(MouseEvent e, PsiMethod method, boolean acceptSelf) { + PsiMethod[] superMethods = composeSuperMethods(method, acceptSelf); + if (superMethods == null) return; boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature(superMethods); PsiElementListNavigator.openTargets(e, superMethods, DaemonBundle.message("navigation.title.super.method", method.getName()), @@ -100,6 +100,22 @@ public class MarkerType { new MethodCellRenderer(showMethodNames)); } + @Nullable + private static PsiMethod[] composeSuperMethods(PsiMethod method, boolean acceptSelf) { + PsiMethod[] superMethods = method.findSuperMethods(false); + if (acceptSelf) { + superMethods = ArrayUtil.prepend(method, superMethods); + } + if (superMethods.length == 0) return null; + return superMethods; + } + + private static PsiElement getParentMethod(PsiElement element) { + final PsiElement parent = element.getParent(); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(element); + return interfaceMethod != null ? interfaceMethod : parent; + } + public static final String SEARCHING_FOR_OVERRIDING_METHODS = "Searching for overriding methods"; public static final MarkerType OVERRIDEN_METHOD = new MarkerType(new NullableFunction<PsiElement, String>() { @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java index ccb1c3c369e4..5d51949c1d6b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.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. @@ -52,7 +52,9 @@ public class AddExceptionToCatchFix extends BaseIntentionAction { PsiDocumentManager.getInstance(project).commitAllDocuments(); PsiElement element = findElement(file, offset); - PsiTryStatement tryStatement = (PsiTryStatement) element.getParent(); + if (element == null) return; + + PsiTryStatement tryStatement = (PsiTryStatement)element.getParent(); List<PsiClassType> unhandledExceptions = new ArrayList<PsiClassType>(ExceptionUtil.collectUnhandledExceptions(element, null)); ExceptionUtil.sortExceptionsByHierarchy(unhandledExceptions); @@ -86,7 +88,9 @@ public class AddExceptionToCatchFix extends BaseIntentionAction { } } - private static PsiCodeBlock addCatchStatement(PsiTryStatement tryStatement, PsiClassType exceptionType, PsiFile file) throws IncorrectOperationException { + private static PsiCodeBlock addCatchStatement(PsiTryStatement tryStatement, + PsiClassType exceptionType, + PsiFile file) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory(); if (tryStatement.getTryBlock() == null) { @@ -108,9 +112,12 @@ public class AddExceptionToCatchFix extends BaseIntentionAction { } PsiParameter[] parameters = tryStatement.getCatchBlockParameters(); - parameters[parameters.length - 1].getTypeElement().replace(factory.createTypeElement(exceptionType)); - PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + PsiTypeElement typeElement = parameters[parameters.length - 1].getTypeElement(); + if (typeElement != null) { + JavaCodeStyleManager.getInstance(file.getProject()).shortenClassReferences(typeElement); + } + PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); return catchBlocks[catchBlocks.length - 1]; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java index 19a4639a0689..69800e5616f7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java @@ -200,7 +200,7 @@ public class StaticImportMethodFix implements IntentionAction { //do not show methods from default package && !((PsiJavaFile)file).getPackageName().isEmpty() && PsiUtil.isAccessible(file.getProject(), method, element, containingClass)) { - if (method.isDeprecated()) { + if (isEffectivelyDeprecated(method)) { deprecated.put(containingClass, method); return processCondition(); } @@ -209,6 +209,20 @@ public class StaticImportMethodFix implements IntentionAction { return processCondition(); } + private boolean isEffectivelyDeprecated(PsiMethod method) { + if (method.isDeprecated()) { + return true; + } + PsiClass aClass = method.getContainingClass(); + while (aClass != null) { + if (aClass.isDeprecated()) { + return true; + } + aClass = aClass.getContainingClass(); + } + return false; + } + private boolean processCondition() { return (applicableList.isEmpty() ? list : applicableList).size() + deprecated.size() < 50; } diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/AnnotationParameterInfoHandler.java b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/AnnotationParameterInfoHandler.java index e72756865767..0d822feff94c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/AnnotationParameterInfoHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/AnnotationParameterInfoHandler.java @@ -21,7 +21,6 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import com.intellij.util.text.CharArrayUtil; -import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -119,9 +118,9 @@ public class AnnotationParameterInfoHandler implements ParameterInfoHandler<PsiA @NonNls StringBuilder buffer = new StringBuilder(); buffer.append(p.getReturnType().getPresentableText()); buffer.append(" "); - int highlightStartOffset = XmlStringUtil.escapeString(buffer.toString()).length(); + int highlightStartOffset = buffer.length(); buffer.append(p.getName()); - int highlightEndOffset = XmlStringUtil.escapeString(buffer.toString()).length(); + int highlightEndOffset = buffer.length(); buffer.append("()"); if (p.getDefaultValue() != null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java index 5da27d9c18d3..b3918fd0fbe2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java @@ -32,7 +32,6 @@ import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashSet; -import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -393,7 +392,7 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc for (int j = 0; j < numParams; j++) { PsiParameter param = parms[j]; - int startOffset = XmlStringUtil.escapeString(buffer.toString()).length(); + int startOffset = buffer.length(); if (param.isValid()) { PsiType paramType = param.getType(); @@ -411,7 +410,7 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc } } - int endOffset = XmlStringUtil.escapeString(buffer.toString()).length(); + int endOffset = buffer.length(); if (j < numParams - 1) { buffer.append(", "); diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java index 2b839b5dfcde..daf5aa5eac74 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java @@ -26,13 +26,11 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.intention.AddAnnotationFix; import com.intellij.codeInsight.intention.AddAnnotationPsiFix; -import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -49,22 +47,11 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction { // include not in project files @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - CaretModel caretModel = editor.getCaretModel(); - int position = caretModel.getOffset(); - PsiElement element = file.findElementAt(position); - return element != null && isAvailable(project, element); - } - - public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement element) { - if (!element.isValid()) return false; - final PsiModifierListOwner owner; - if (!element.getManager().isInProject(element) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) { - owner = AddAnnotationPsiFix.getContainer(element); - } - else { + final PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(file, editor.getCaretModel().getOffset()); + if (owner == null || + owner.getManager().isInProject(owner) && !CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) { return false; } - if (owner == null) return false; Pair<String, String[]> annotations = getAnnotations(project); String toAdd = annotations.first; String[] toRemove = annotations.second; @@ -82,11 +69,7 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction { @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - CaretModel caretModel = editor.getCaretModel(); - int position = caretModel.getOffset(); - PsiElement element = file.findElementAt(position); - - PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(element); + PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(file, editor.getCaretModel().getOffset()); if (owner == null || !owner.isValid()) return; Pair<String, String[]> annotations = getAnnotations(project); String toAdd = annotations.first; diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/BaseColorIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/BaseColorIntentionAction.java index adde45b86af6..f3c9df9dfe16 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/BaseColorIntentionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/BaseColorIntentionAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,9 +28,11 @@ import static com.intellij.patterns.PlatformPatterns.psiElement; /** * @author Danila Ponomarenko + * @author Konstantin Bulenkov */ public abstract class BaseColorIntentionAction extends PsiElementBaseIntentionAction implements HighPriorityAction { protected static final String JAVA_AWT_COLOR = "java.awt.Color"; + protected static final String COLOR_UI_RESOURCE = "javax.swing.plaf.ColorUIResource"; @Override public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { @@ -39,29 +41,28 @@ public abstract class BaseColorIntentionAction extends PsiElementBaseIntentionAc } final PsiNewExpression expression = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class, false); - if (expression == null) { - return false; - } - - return isJavaAwtColor(expression.getClassOrAnonymousClassReference()) && isValueArguments(expression.getArgumentList()); + return expression != null + && isJavaAwtColor(expression.getClassOrAnonymousClassReference()) + && isValueArguments(expression.getArgumentList()); } private static boolean isJavaAwtColor(@Nullable PsiJavaCodeReferenceElement ref) { - if (ref == null) { - return false; - } - - final PsiReference reference = ref.getReference(); - if (reference == null) { - return false; - } + final String fqn = getFqn(ref); + return JAVA_AWT_COLOR.equals(fqn) || COLOR_UI_RESOURCE.equals(fqn); + } - final PsiElement psiElement = reference.resolve(); - if (psiElement instanceof PsiClass && JAVA_AWT_COLOR.equals(((PsiClass)psiElement).getQualifiedName())) { - return true; + @Nullable + protected static String getFqn(@Nullable PsiJavaCodeReferenceElement ref) { + if (ref != null) { + final PsiReference reference = ref.getReference(); + if (reference != null) { + final PsiElement psiElement = reference.resolve(); + if (psiElement instanceof PsiClass) { + return ((PsiClass)psiElement).getQualifiedName(); + } + } } - - return false; + return null; } private static boolean isValueArguments(@Nullable PsiExpressionList arguments) { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ColorChooserIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ColorChooserIntentionAction.java index db93d4e851f5..f5d1b3a28afe 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ColorChooserIntentionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ColorChooserIntentionAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -191,7 +191,7 @@ public class ColorChooserIntentionAction extends BaseColorIntentionAction { final PsiManager manager = expression.getManager(); final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); final PsiExpression newCall = factory.createExpressionFromText( - "new " + JAVA_AWT_COLOR + "(" + "new " + getFqn(expression.getClassOrAnonymousClassReference()) + "(" + color.getRed() + ", " + color.getGreen() + ", " + color.getBlue() diff --git a/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java b/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java index 94ddb7ae863e..55d82a987001 100644 --- a/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java @@ -30,6 +30,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.FindSuperElementsHelper; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -65,20 +66,27 @@ public class JavaGotoSuperHandler implements CodeInsightActionHandler { @Nullable private PsiElement[] findSuperElements(PsiFile file, int offset) { - PsiNameIdentifierOwner parent = getElement(file, offset); - if (parent == null) return null; + PsiElement element = getElement(file, offset); + if (element == null) return null; + + final PsiExpression expression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class, PsiMethodReferenceExpression.class); + if (expression != null) { + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(expression); + if (interfaceMethod != null) { + return ArrayUtil.prepend(interfaceMethod, interfaceMethod.findSuperMethods(false)); + } + } + + final PsiNameIdentifierOwner parent = PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class, PsiClass.class); + if (parent == null) { + return null; + } return FindSuperElementsHelper.findSuperElements(parent); } - protected PsiNameIdentifierOwner getElement(PsiFile file, int offset) { - PsiElement element = file.findElementAt(offset); - if (element == null) return null; - - PsiNameIdentifierOwner parent = PsiTreeUtil.getParentOfType(element, PsiMethod.class, PsiClass.class); - if (parent == null) - return null; - return parent; + protected PsiElement getElement(PsiFile file, int offset) { + return file.findElementAt(offset); } @Override diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/EditContractIntention.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/EditContractIntention.java index 7040347c4d0e..767077b3448e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/EditContractIntention.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/EditContractIntention.java @@ -28,7 +28,6 @@ import com.intellij.openapi.ui.InputValidatorEx; import com.intellij.openapi.ui.Messages; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -48,22 +47,15 @@ public class EditContractIntention extends BaseIntentionAction { @Nullable private static PsiMethod getTargetMethod(@NotNull Project project, Editor editor, PsiFile file) { - PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); - if (element == null) return null; - if (!element.getManager().isInProject(element) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) { - final PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(element); - if (owner instanceof PsiMethod) { - PsiElement original = owner.getOriginalElement(); - if (original instanceof PsiMethod) { - return (PsiMethod)original; - } - return (PsiMethod)owner; - } + final PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(file, editor.getCaretModel().getOffset()); + if (owner instanceof PsiMethod && + (!owner.getManager().isInProject(owner) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS)) { + PsiElement original = owner.getOriginalElement(); + return original instanceof PsiMethod ? (PsiMethod)original : (PsiMethod)owner; } return null; } - @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { final PsiMethod method = getTargetMethod(project, editor, file); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaReferenceAdjuster.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaReferenceAdjuster.java index db020ad58b8b..42d3098b7b07 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaReferenceAdjuster.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaReferenceAdjuster.java @@ -60,6 +60,12 @@ public class JavaReferenceAdjuster implements ReferenceAdjuster { } if (rightKind) { + // annotations may jump out of reference (see PsiJavaCodeReferenceImpl#setAnnotations()) so they should be processed first + List<PsiAnnotation> annotations = PsiTreeUtil.getChildrenOfTypeAsList(ref, PsiAnnotation.class); + for (PsiAnnotation annotation : annotations) { + process(annotation.getNode(), addImports, incompleteCode, useFqInJavadoc, useFqInCode); + } + boolean isInsideDocComment = TreeUtil.findParent(element, JavaDocElementType.DOC_COMMENT) != null; boolean isShort = !ref.isQualified(); if (isInsideDocComment ? !useFqInJavadoc : !useFqInCode) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReferenceSet.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReferenceSet.java index c184775ad11b..dbcbfdc4e546 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReferenceSet.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReferenceSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -44,27 +45,29 @@ public class JavaClassReferenceSet { private final int myStartInElement; private final JavaClassReferenceProvider myProvider; - public JavaClassReferenceSet(String str, PsiElement element, int startInElement, final boolean isStatic, JavaClassReferenceProvider provider) { + public JavaClassReferenceSet(@NotNull String str, @NotNull PsiElement element, int startInElement, final boolean isStatic, @NotNull JavaClassReferenceProvider provider) { this(str, element, startInElement, isStatic, provider, null); } - private JavaClassReferenceSet(String str, PsiElement element, int startInElement, final boolean isStatic, JavaClassReferenceProvider provider, + private JavaClassReferenceSet(@NotNull String str, @NotNull PsiElement element, int startInElement, final boolean isStatic, @NotNull JavaClassReferenceProvider provider, JavaClassReferenceSet context) { myStartInElement = startInElement; myProvider = provider; reparse(str, element, isStatic, context); } + @NotNull public JavaClassReferenceProvider getProvider() { return myProvider; } + @NotNull public TextRange getRangeInElement() { PsiReference[] references = getReferences(); return new TextRange(references[0].getRangeInElement().getStartOffset(), references[references.length - 1].getRangeInElement().getEndOffset()); } - private void reparse(String str, PsiElement element, final boolean isStaticImport, JavaClassReferenceSet context) { + private void reparse(@NotNull String str, @NotNull PsiElement element, final boolean isStaticImport, JavaClassReferenceSet context) { myElement = element; myContext = context; final List<JavaClassReference> referencesList = new ArrayList<JavaClassReference>(); @@ -186,7 +189,8 @@ public class JavaClassReferenceSet { myReferences = referencesList.toArray(new JavaClassReference[referencesList.size()]); } - protected JavaClassReference createReference(final int referenceIndex, final String subreferenceText, final TextRange textRange, + @NotNull + protected JavaClassReference createReference(final int referenceIndex, @NotNull String subreferenceText, @NotNull TextRange textRange, final boolean staticImport) { return new JavaClassReference(this, textRange, referenceIndex, subreferenceText, staticImport); } @@ -200,7 +204,7 @@ public class JavaClassReferenceSet { return isAllowDollarInNames() ? c == DOLLAR : c == DOT; } - public void reparse(PsiElement element, final TextRange range) { + public void reparse(@NotNull PsiElement element, @NotNull TextRange range) { final String text = range.substring(element.getText()); reparse(text, element, false, myContext); } @@ -209,6 +213,7 @@ public class JavaClassReferenceSet { return myReferences[index]; } + @NotNull public JavaClassReference[] getAllReferences() { JavaClassReference[] result = myReferences; if (myNestedGenericParameterReferences != null) { @@ -229,10 +234,12 @@ public class JavaClassReferenceSet { return myProvider.isSoft(); } + @NotNull public PsiElement getElement() { return myElement; } + @NotNull public PsiReference[] getReferences() { return myReferences; } @@ -243,6 +250,7 @@ public class JavaClassReferenceSet { } @SuppressWarnings({"UnresolvedPropertyKey"}) + @NotNull public String getUnresolvedMessagePattern(int index){ if (canReferencePackage(index)) { return JavaErrorMessages.message("error.cannot.resolve.class.or.package"); diff --git a/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java b/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java index ee207fb89fc7..a32dc464f7fa 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureProcessor.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. @@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiUtil; @@ -187,27 +188,28 @@ public class ChangeClassSignatureProcessor extends BaseRefactoringProcessor { ChangeSignatureUtil.synchronizeList(myClass.getTypeParameterList(), newTypeParameters, TypeParameterList.INSTANCE, toRemoveParms); } - private boolean[] detectRemovedParameters(final PsiTypeParameter[] originaltypeParameters) { - final boolean[] toRemoveParms = new boolean[originaltypeParameters.length]; - Arrays.fill(toRemoveParms, true); + private boolean[] detectRemovedParameters(final PsiTypeParameter[] original) { + final boolean[] toRemove = new boolean[original.length]; + Arrays.fill(toRemove, true); for (final TypeParameterInfo info : myNewSignature) { int oldParameterIndex = info.getOldParameterIndex(); if (oldParameterIndex >= 0) { - toRemoveParms[oldParameterIndex] = false; + toRemove[oldParameterIndex] = false; } } - return toRemoveParms; + return toRemove; } - private void processUsage(final UsageInfo usage, final PsiTypeParameter[] originalTypeParameters, final boolean[] toRemoveParms) - throws IncorrectOperationException { + private void processUsage(UsageInfo usage, PsiTypeParameter[] original, boolean[] toRemove) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)usage.getElement(); + assert referenceElement != null : usage; PsiSubstitutor usageSubstitutor = determineUsageSubstitutor(referenceElement); PsiReferenceParameterList referenceParameterList = referenceElement.getParameterList(); + assert referenceParameterList != null : referenceElement; PsiTypeElement[] oldValues = referenceParameterList.getTypeParameterElements(); - if (oldValues.length != originalTypeParameters.length) return; + if (oldValues.length != original.length) return; List<PsiTypeElement> newValues = new ArrayList<PsiTypeElement>(); for (final TypeParameterInfo info : myNewSignature) { int oldIndex = info.getOldParameterIndex(); @@ -221,7 +223,9 @@ public class ChangeClassSignatureProcessor extends BaseRefactoringProcessor { newValues.add(newValue); } } - ChangeSignatureUtil.synchronizeList(referenceParameterList, newValues, ReferenceParameterList.INSTANCE, toRemoveParms); + + ChangeSignatureUtil.synchronizeList(referenceParameterList, newValues, ReferenceParameterList.INSTANCE, toRemove); + JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(referenceParameterList); } private PsiSubstitutor determineUsageSubstitutor(PsiJavaCodeReferenceElement referenceElement) { diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/ParameterInfoImpl.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/ParameterInfoImpl.java index aa27a6e024ca..69fc99031e80 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/ParameterInfoImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/ParameterInfoImpl.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,11 +33,13 @@ import java.util.ArrayList; import java.util.List; public class ParameterInfoImpl implements JavaParameterInfo { + public static final ParameterInfoImpl[] EMPTY_ARRAY = {}; + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.ParameterInfoImpl"); + public int oldParameterIndex; - boolean useAnySingleVariable; + private boolean useAnySingleVariable; private String name = ""; - public static final ParameterInfoImpl[] EMPTY_ARRAY = new ParameterInfoImpl[0]; private CanonicalTypes.Type myType; String defaultValue = ""; diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java index 25a9481259d8..2b483ddb676c 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.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. @@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; @@ -259,9 +260,13 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor { new InlineToAnonymousConstructorProcessor(myClass, psiNewExpression, superType).run(); } else { - PsiJavaCodeReferenceElement element = - JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory().createClassReferenceElement(superType.resolve()); - psiNewExpression.getClassReference().replace(element); + PsiClass target = superType.resolve(); + assert target != null : superType; + PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); + PsiJavaCodeReferenceElement element = factory.createClassReferenceElement(target); + PsiJavaCodeReferenceElement reference = psiNewExpression.getClassReference(); + assert reference != null : psiNewExpression; + reference.replace(element); } } catch (IncorrectOperationException e) { @@ -276,7 +281,8 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor { PsiType substType = classResolveResult.getSubstitutor().substitute(superType); assert classResolveResult.getElement() == myClass; try { - typeElement.replace(factory.createTypeElement(substType)); + PsiElement replaced = typeElement.replace(factory.createTypeElement(substType)); + JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(replaced); } catch(IncorrectOperationException e) { LOG.error(e); diff --git a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/usageInfo/ReplaceWithSubtypeUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/usageInfo/ReplaceWithSubtypeUsageInfo.java index f2a6a2e647a2..ec1e10df935b 100644 --- a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/usageInfo/ReplaceWithSubtypeUsageInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/usageInfo/ReplaceWithSubtypeUsageInfo.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. @@ -13,21 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * User: anna - * Date: 27-Aug-2008 - */ package com.intellij.refactoring.inlineSuperClass.usageInfo; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.util.FixableUsageInfo; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +/** + * @author anna + * @since 27-Aug-2008 + */ public class ReplaceWithSubtypeUsageInfo extends FixableUsageInfo { public static final Logger LOG = Logger.getInstance("#" + ReplaceWithSubtypeUsageInfo.class.getName()); private final PsiTypeElement myTypeElement; @@ -51,8 +52,10 @@ public class ReplaceWithSubtypeUsageInfo extends FixableUsageInfo { public void fixUsage() throws IncorrectOperationException { if (myTypeElement.isValid()) { - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myTypeElement.getProject()).getElementFactory(); - myTypeElement.replace(elementFactory.createTypeElement(myTargetClassType)); + Project project = myTypeElement.getProject(); + PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); + PsiElement replaced = myTypeElement.replace(elementFactory.createTypeElement(myTargetClassType)); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced); } } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesImpl.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesImpl.java index 6d333e9cb54b..3e92a19373ab 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesImpl.java @@ -23,6 +23,7 @@ package com.intellij.refactoring.move.moveClassesOrPackages; import com.intellij.history.LocalHistory; import com.intellij.history.LocalHistoryAction; import com.intellij.ide.util.DirectoryChooser; +import com.intellij.ide.util.PlatformPackageUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; @@ -266,7 +267,8 @@ public class MoveClassesOrPackagesImpl { return aPackage != null ? getTargetPackageNameForMovedElement(aPackage) : ""; } else if (psiElement != null) { - PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(psiElement.getContainingFile().getContainingDirectory()); + PsiDirectory directory = PlatformPackageUtil.getDirectory(psiElement); + PsiPackage aPackage = directory == null ? null : JavaDirectoryService.getInstance().getPackage(directory); return aPackage != null ? aPackage.getQualifiedName() : ""; } else { diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationReplacementUtil.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationReplacementUtil.java index f6cdabacedad..0004ff456cb6 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationReplacementUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationReplacementUtil.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. @@ -18,6 +18,7 @@ package com.intellij.refactoring.typeMigration; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.impl.PsiDiamondTypeUtil; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.CompositeElement; @@ -109,18 +110,19 @@ public class TypeMigrationReplacementUtil { if (!migratedType.isValid()) { migratedType = JavaPsiFacade.getElementFactory(project).createTypeByFQClassName(migratedType.getCanonicalText()); } - final PsiTypeElement typeElement = - JavaPsiFacade.getInstance(project).getElementFactory().createTypeElement(migratedType); + final PsiTypeElement typeElement = JavaPsiFacade.getInstance(project).getElementFactory().createTypeElement(migratedType); if (element instanceof PsiMethod) { final PsiTypeElement returnTypeElement = ((PsiMethod)element).getReturnTypeElement(); if (returnTypeElement != null) { - returnTypeElement.replace(typeElement); + final PsiElement replaced = returnTypeElement.replace(typeElement); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced); } } else if (element instanceof PsiVariable) { final PsiTypeElement varTypeElement = ((PsiVariable)element).getTypeElement(); if (varTypeElement != null) { - varTypeElement.replace(typeElement); + final PsiElement replaced = varTypeElement.replace(typeElement); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced); } } else { diff --git a/java/java-impl/src/com/intellij/spi/SPIGotoSuperHandler.java b/java/java-impl/src/com/intellij/spi/SPIGotoSuperHandler.java index 04c48bc71e40..966a7a3422ea 100644 --- a/java/java-impl/src/com/intellij/spi/SPIGotoSuperHandler.java +++ b/java/java-impl/src/com/intellij/spi/SPIGotoSuperHandler.java @@ -16,9 +16,8 @@ package com.intellij.spi; import com.intellij.codeInsight.navigation.JavaGotoSuperHandler; -import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.spi.psi.SPIClassProviderReferenceElement; @@ -27,11 +26,11 @@ import com.intellij.spi.psi.SPIClassProviderReferenceElement; */ public class SPIGotoSuperHandler extends JavaGotoSuperHandler { @Override - protected PsiNameIdentifierOwner getElement(PsiFile file, int offset) { + protected PsiElement getElement(PsiFile file, int offset) { final SPIClassProviderReferenceElement - providerElement = PsiTreeUtil.getParentOfType(file.findElementAt(offset), SPIClassProviderReferenceElement.class); + providerElement = PsiTreeUtil.getParentOfType(super.getElement(file, offset), SPIClassProviderReferenceElement.class); if (providerElement != null) { - return (PsiClass)providerElement.resolve(); + return providerElement.resolve(); } return null; diff --git a/java/java-impl/src/com/intellij/util/xml/CanonicalPsiTypeConverterImpl.java b/java/java-impl/src/com/intellij/util/xml/CanonicalPsiTypeConverterImpl.java index 877d27453b1b..254dc036547c 100644 --- a/java/java-impl/src/com/intellij/util/xml/CanonicalPsiTypeConverterImpl.java +++ b/java/java-impl/src/com/intellij/util/xml/CanonicalPsiTypeConverterImpl.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. @@ -80,7 +80,8 @@ public class CanonicalPsiTypeConverterImpl extends CanonicalPsiTypeConverter imp final boolean isPrimitiveType = type instanceof PsiPrimitiveType; return new JavaClassReferenceSet(trimmed, element, offset, false, CLASS_REFERENCE_PROVIDER) { - protected JavaClassReference createReference(int refIndex, String subRefText, TextRange textRange, boolean staticImport) { + @NotNull + protected JavaClassReference createReference(int refIndex, @NotNull String subRefText, @NotNull TextRange textRange, boolean staticImport) { return new JavaClassReference(this, textRange, refIndex, subRefText, staticImport) { public boolean isSoft() { return true; diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.java index 59c7d6505859..b25f8c50911f 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.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. @@ -20,6 +20,7 @@ package com.intellij.psi.impl.search; import com.intellij.ide.highlighter.JavaClassFileType; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.JdkOrderEntry; import com.intellij.openapi.roots.OrderEntry; @@ -30,13 +31,25 @@ import com.intellij.psi.SdkResolveScopeProvider; import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class JavaSourceFilterScope extends DelegatingGlobalSearchScope { + private static final Logger LOG = Logger.getInstance(JavaSourceFilterScope.class); + + @Nullable private final ProjectFileIndex myIndex; public JavaSourceFilterScope(@NotNull final GlobalSearchScope delegate) { super(delegate); - myIndex = ProjectRootManager.getInstance(getProject()).getFileIndex(); + + Project project = getProject(); + if (project != null) { + myIndex = ProjectRootManager.getInstance(project).getFileIndex(); + } + else { + myIndex = null; + LOG.error("delegate.getProject() == null, delegate.getClass() == " + delegate.getClass()); + } } @Override @@ -45,6 +58,10 @@ public class JavaSourceFilterScope extends DelegatingGlobalSearchScope { return false; } + if (myIndex == null) { + return false; + } + if (JavaClassFileType.INSTANCE == file.getFileType()) { return myIndex.isInLibraryClasses(file); } diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java index 8c36cfae1b88..577d38a30a15 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -519,6 +519,14 @@ public class GenericsUtil { else if (type instanceof PsiArrayType) { return checkNotAssignable(bound, type, true); } + else if (type instanceof PsiIntersectionType) { + for (PsiType psiType : ((PsiIntersectionType)type).getConjuncts()) { + if (!checkNotInBounds(psiType, bound, uncheckedConversionByDefault)) { + return false; + } + } + return true; + } return false; } diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 15b3208b7426..54bd0241e64e 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -60,6 +60,16 @@ public class LambdaUtil { return getFunctionalInterfaceMethod(PsiUtil.resolveGenericsClassInType(functionalInterfaceType)); } + public static PsiMethod getFunctionalInterfaceMethod(@Nullable PsiElement element) { + if (element instanceof PsiLambdaExpression || element instanceof PsiMethodReferenceExpression) { + final PsiType samType = element instanceof PsiLambdaExpression + ? ((PsiLambdaExpression)element).getFunctionalInterfaceType() + : ((PsiMethodReferenceExpression)element).getFunctionalInterfaceType(); + return getFunctionalInterfaceMethod(samType); + } + return null; + } + @Nullable public static PsiMethod getFunctionalInterfaceMethod(PsiClassType.ClassResolveResult result) { final PsiClass psiClass = result.getElement(); @@ -308,7 +318,7 @@ public class LambdaUtil { final int finalLambdaIdx = adjustLambdaIdx(lambdaIdx, (PsiMethod)resolve, parameters); if (finalLambdaIdx < parameters.length) { if (!tryToSubstitute) return getNormalizedType(parameters[finalLambdaIdx]); - return PsiResolveHelper.ourGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() { + return PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() { @Override public PsiType compute() { return resolveResult.getSubstitutor().substitute(getNormalizedType(parameters[finalLambdaIdx])); diff --git a/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java b/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java index bc61565bdc6c..47bd7be64c65 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiArrayType.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. @@ -16,7 +16,6 @@ package com.intellij.psi; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; /** @@ -24,7 +23,7 @@ import org.jetbrains.annotations.NotNull; * * @author max */ -public class PsiArrayType extends PsiType { +public class PsiArrayType extends PsiType.Stub { private final PsiType myComponentType; /** @@ -44,19 +43,33 @@ public class PsiArrayType extends PsiType { @NotNull @Override public String getPresentableText() { - return StringUtil.join(myComponentType.getPresentableText(), getAnnotationsTextPrefix(false, true, true), "[]"); + return getText(myComponentType.getPresentableText(), "[]", false, true); } @NotNull @Override - public String getCanonicalText() { - return StringUtil.join(myComponentType.getCanonicalText(), "[]"); + public String getCanonicalText(boolean annotated) { + return getText(myComponentType.getCanonicalText(annotated), "[]", true, annotated); } @NotNull @Override public String getInternalCanonicalText() { - return StringUtil.join(myComponentType.getInternalCanonicalText(), getAnnotationsTextPrefix(true, true, true), "[]"); + return getText(myComponentType.getInternalCanonicalText(), "[]", true, true); + } + + protected String getText(@NotNull String prefix, @NotNull String suffix, boolean qualified, boolean annotated) { + StringBuilder sb = new StringBuilder(prefix.length() + suffix.length()); + sb.append(prefix); + if (annotated) { + PsiAnnotation[] annotations = getAnnotations(); + if (annotations.length != 0) { + sb.append(' '); + PsiNameHelper.appendAnnotations(sb, annotations, qualified); + } + } + sb.append(suffix); + return sb.toString(); } @Override diff --git a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java index 6de8d0202bef..8130b864ad9a 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable; /** * @author ven */ -public class PsiCapturedWildcardType extends PsiType { +public class PsiCapturedWildcardType extends PsiType.Stub { @NotNull private final PsiWildcardType myExistential; @NotNull private final PsiElement myContext; @Nullable private final PsiTypeParameter myParameter; @@ -78,8 +78,8 @@ public class PsiCapturedWildcardType extends PsiType { @NotNull @Override - public String getCanonicalText() { - return myExistential.getCanonicalText(); + public String getCanonicalText(boolean annotated) { + return myExistential.getCanonicalText(annotated); } @NotNull diff --git a/java/java-psi-api/src/com/intellij/psi/PsiClassType.java b/java/java-psi-api/src/com/intellij/psi/PsiClassType.java index 30d9570048a7..722b9e2816a2 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiClassType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiClassType.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. @@ -280,4 +280,23 @@ public abstract class PsiClassType extends PsiType { } }; } + + /** + * Temporary class to facilitate transition to {@link #getCanonicalText(boolean)}. + */ + public static abstract class Stub extends PsiClassType { + protected Stub(LanguageLevel languageLevel, @NotNull PsiAnnotation[] annotations) { + super(languageLevel, annotations); + } + + @NotNull + @Override + public final String getCanonicalText() { + return getCanonicalText(false); + } + + @NotNull + @Override + public abstract String getCanonicalText(boolean annotated); + } } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java b/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java index e9e0cf3116c4..1a4062e294fe 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.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. @@ -33,7 +33,7 @@ import java.util.List; * Composite type resulting from Project Coin's multi-catch statements, i.e. <code>FileNotFoundException | EOFException</code>. * In most cases should be threatened via its least upper bound (<code>IOException</code> in the example above). */ -public class PsiDisjunctionType extends PsiType { +public class PsiDisjunctionType extends PsiType.Stub { private final PsiManager myManager; private final List<PsiType> myTypes; private final CachedValue<PsiType> myLubCache; @@ -85,15 +85,21 @@ public class PsiDisjunctionType extends PsiType { @Override public String getPresentableText() { return StringUtil.join(myTypes, new Function<PsiType, String>() { - @Override public String fun(PsiType psiType) { return psiType.getPresentableText(); } + @Override + public String fun(PsiType psiType) { + return psiType.getPresentableText(); + } }, " | "); } @NotNull @Override - public String getCanonicalText() { + public String getCanonicalText(final boolean annotated) { return StringUtil.join(myTypes, new Function<PsiType, String>() { - @Override public String fun(PsiType psiType) { return psiType.getCanonicalText(); } + @Override + public String fun(PsiType psiType) { + return psiType.getCanonicalText(annotated); + } }, " | "); } @@ -101,7 +107,10 @@ public class PsiDisjunctionType extends PsiType { @Override public String getInternalCanonicalText() { return StringUtil.join(myTypes, new Function<PsiType, String>() { - @Override public String fun(PsiType psiType) { return psiType.getInternalCanonicalText(); } + @Override + public String fun(PsiType psiType) { + return psiType.getInternalCanonicalText(); + } }, " | "); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java index 0d1447924d83..085854f51a65 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.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. @@ -15,7 +15,6 @@ */ package com.intellij.psi; -import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; /** @@ -45,19 +44,19 @@ public class PsiEllipsisType extends PsiArrayType { @NotNull @Override public String getPresentableText() { - return StringUtil.join(getComponentType().getPresentableText(), getAnnotationsTextPrefix(false, true, true), "..."); + return getText(getComponentType().getPresentableText(), "...", false, true); } @NotNull @Override - public String getCanonicalText() { - return StringUtil.join(getComponentType().getCanonicalText(), "..."); + public String getCanonicalText(boolean annotated) { + return getText(getComponentType().getCanonicalText(annotated), "...", true, annotated); } @NotNull @Override public String getInternalCanonicalText() { - return StringUtil.join(getComponentType().getInternalCanonicalText(), getAnnotationsTextPrefix(true, true, true), "..."); + return getText(getComponentType().getInternalCanonicalText(), "...", true, true); } @Override diff --git a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java index 215bb86b2b81..55a5e9d55260 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.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. @@ -29,7 +29,7 @@ import java.util.*; * * @author ven */ -public class PsiIntersectionType extends PsiType { +public class PsiIntersectionType extends PsiType.Stub { private final PsiType[] myConjuncts; private PsiIntersectionType(@NotNull PsiType[] conjuncts) { @@ -78,7 +78,8 @@ public class PsiIntersectionType extends PsiType { for (PsiType existing : array) { if (type != existing) { final boolean allowUncheckedConversion = type instanceof PsiClassType && ((PsiClassType)type).isRaw(); - if (TypeConversionUtil.isAssignable(type, existing, allowUncheckedConversion)) { + if (TypeConversionUtil.isAssignable(GenericsUtil.eliminateWildcards(type), + GenericsUtil.eliminateWildcards(existing), allowUncheckedConversion)) { iterator.remove(); break; } @@ -110,19 +111,19 @@ public class PsiIntersectionType extends PsiType { @NotNull @Override - public String getCanonicalText() { - return myConjuncts[0].getCanonicalText(); + public String getCanonicalText(boolean annotated) { + return myConjuncts[0].getCanonicalText(annotated); } @NotNull @Override public String getInternalCanonicalText() { - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < myConjuncts.length; i++) { - buffer.append(myConjuncts[i].getInternalCanonicalText()); - if (i < myConjuncts.length - 1) buffer.append(" & "); - } - return buffer.toString(); + return StringUtil.join(myConjuncts, new Function<PsiType, String>() { + @Override + public String fun(PsiType psiType) { + return psiType.getInternalCanonicalText(); + } + }, " & "); } @Override diff --git a/java/java-psi-api/src/com/intellij/psi/PsiNameHelper.java b/java/java-psi-api/src/com/intellij/psi/PsiNameHelper.java index 6ae0fa6a081f..6e5e6563dc3b 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiNameHelper.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiNameHelper.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. @@ -23,8 +23,11 @@ import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.List; import java.util.regex.Pattern; +import static com.intellij.util.ObjectUtils.assertNotNull; import static com.intellij.util.ObjectUtils.notNull; /** @@ -37,7 +40,7 @@ public abstract class PsiNameHelper { public static PsiNameHelper getInstance(Project project) { return ServiceManager.getService(project, PsiNameHelper.class); } - + /** * Checks if the specified text is a Java identifier, using the language level of the project * with which the name helper is associated to filter out keywords. @@ -121,30 +124,15 @@ public abstract class PsiNameHelper { } @NotNull - public static String getPresentableText(@Nullable String refName, @NotNull PsiAnnotation[] annotations, @NotNull PsiType[] typeParameters) { - if (typeParameters.length == 0 && annotations.length == 0) { + public static String getPresentableText(@Nullable String refName, @NotNull PsiAnnotation[] annotations, @NotNull PsiType[] types) { + if (types.length == 0 && annotations.length == 0) { return refName != null ? refName : ""; } StringBuilder buffer = new StringBuilder(); - - if (annotations.length > 0) { - for (PsiAnnotation annotation : annotations) { - buffer.append(annotation.getText()).append(' '); - } - } - + appendAnnotations(buffer, annotations, false); buffer.append(refName); - - if (typeParameters.length > 0) { - buffer.append("<"); - for (int i = 0; i < typeParameters.length; i++) { - buffer.append(typeParameters[i].getPresentableText()); - if (i < typeParameters.length - 1) buffer.append(", "); - } - buffer.append(">"); - } - + appendTypeArgs(buffer, types, false, true); return buffer.toString(); } @@ -262,4 +250,43 @@ public abstract class PsiNameHelper { return subpackageName.equals(packageName) || subpackageName.startsWith(packageName) && subpackageName.charAt(packageName.length()) == '.'; } + + public static void appendTypeArgs(@NotNull StringBuilder sb, @NotNull PsiType[] types, boolean canonical, boolean annotated) { + if (types.length == 0) return; + + sb.append('<'); + for (int i = 0; i < types.length; i++) { + if (i > 0) { + sb.append(canonical ? "," : ", "); + } + + PsiType type = types[i]; + if (canonical) { + sb.append(type.getCanonicalText(annotated)); + } + else { + sb.append(type.getPresentableText()); + } + } + sb.append('>'); + } + + public static boolean appendAnnotations(@NotNull StringBuilder sb, @NotNull PsiAnnotation[] annotations, boolean canonical) { + return appendAnnotations(sb, Arrays.asList(annotations), canonical); + } + + public static boolean appendAnnotations(@NotNull StringBuilder sb, @NotNull List<PsiAnnotation> annotations, boolean canonical) { + for (PsiAnnotation annotation : annotations) { + sb.append('@'); + if (canonical) { + sb.append(annotation.getQualifiedName()); + sb.append(annotation.getParameterList().getText()); + } + else { + sb.append(assertNotNull(annotation.getNameReferenceElement()).getText()); + } + sb.append(' '); + } + return annotations.size() > 0; + } } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java index dd6b0d4d6ef9..cad6cfda7234 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java @@ -30,7 +30,7 @@ import java.util.Map; /** * Represents primitive types of Java language. */ -public class PsiPrimitiveType extends PsiType { +public class PsiPrimitiveType extends PsiType.Stub { private static final Map<String, PsiPrimitiveType> ourQNameToUnboxed = new THashMap<String, PsiPrimitiveType>(); private static final Map<PsiPrimitiveType, String> ourUnboxedToQName = new THashMap<PsiPrimitiveType, String>(); @@ -52,19 +52,29 @@ public class PsiPrimitiveType extends PsiType { @NotNull @Override public String getPresentableText() { - return getAnnotationsTextPrefix(false, false, true) + myName; + return getText(false, true); } @NotNull @Override - public String getCanonicalText() { - return myName; + public String getCanonicalText(boolean annotated) { + return getText(true, annotated); } @NotNull @Override public String getInternalCanonicalText() { - return getAnnotationsTextPrefix(true, false, true) + myName; + return getText(true, true); + } + + private String getText(boolean qualified, boolean annotated) { + PsiAnnotation[] annotations = getAnnotations(); + if (!annotated || annotations.length == 0) return myName; + + StringBuilder sb = new StringBuilder(); + PsiNameHelper.appendAnnotations(sb, annotations, qualified); + sb.append(myName); + return sb.toString(); } /** diff --git a/java/java-psi-api/src/com/intellij/psi/PsiType.java b/java/java-psi-api/src/com/intellij/psi/PsiType.java index cfbf026067bc..1dd67fb31a7f 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiType.java @@ -84,6 +84,15 @@ public abstract class PsiType implements PsiAnnotationOwner { */ @NonNls @NotNull + public String getCanonicalText(boolean annotated) { + return getCanonicalText(); + } + + /** + * Same as {@code getCanonicalText(false)}. + */ + @NonNls + @NotNull public abstract String getCanonicalText(); /** @@ -284,24 +293,15 @@ public abstract class PsiType implements PsiAnnotationOwner { return getAnnotations(); } - @NotNull + /** @deprecated use {@link PsiNameHelper#appendAnnotations(StringBuilder, PsiAnnotation[], boolean)} (to remove in IDEA 14) */ + @SuppressWarnings("UnusedDeclaration") protected String getAnnotationsTextPrefix(boolean qualified, boolean leadingSpace, boolean trailingSpace) { PsiAnnotation[] annotations = getAnnotations(); if (annotations.length == 0) return ""; StringBuilder sb = new StringBuilder(); if (leadingSpace) sb.append(' '); - for (int i = 0; i < annotations.length; i++) { - if (i > 0) sb.append(' '); - PsiAnnotation annotation = annotations[i]; - if (qualified) { - sb.append('@').append(annotation.getQualifiedName()).append(annotation.getParameterList().getText()); - } - else { - sb.append(annotation.getText()); - } - } - if (trailingSpace) sb.append(' '); + if (PsiNameHelper.appendAnnotations(sb, annotations, qualified) &&!trailingSpace) sb.setLength(sb.length() - 1); return sb.toString(); } @@ -310,4 +310,23 @@ public abstract class PsiType implements PsiAnnotationOwner { //noinspection HardCodedStringLiteral return "PsiType:" + getPresentableText(); } + + /** + * Temporary class to facilitate transition to {@link #getCanonicalText(boolean)}. + */ + protected static abstract class Stub extends PsiType { + protected Stub(@NotNull PsiAnnotation[] annotations) { + super(annotations); + } + + @NotNull + @Override + public final String getCanonicalText() { + return getCanonicalText(false); + } + + @NotNull + @Override + public abstract String getCanonicalText(boolean annotated); + } } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java index a3dd77aae361..d6518104b014 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.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. @@ -28,7 +28,7 @@ import org.jetbrains.annotations.Nullable; * * @author dsl */ -public class PsiWildcardType extends PsiType { +public class PsiWildcardType extends PsiType.Stub { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiWildcardType"); private static final Key<PsiWildcardType> UNBOUNDED_WILDCARD = new Key<PsiWildcardType>("UNBOUNDED_WILDCARD"); @@ -83,21 +83,37 @@ public class PsiWildcardType extends PsiType { @NotNull @Override public String getPresentableText() { - return getAnnotationsTextPrefix(false, false, true) + - (myBound == null ? "?" : (myIsExtending ? EXTENDS_PREFIX : SUPER_PREFIX) + myBound.getPresentableText()); + return getText(false, true, myBound == null ? null : myBound.getPresentableText()); } @Override @NotNull - public String getCanonicalText() { - return myBound == null ? "?" : (myIsExtending ? EXTENDS_PREFIX : SUPER_PREFIX) + myBound.getCanonicalText(); + public String getCanonicalText(boolean annotated) { + return getText(true, annotated, myBound == null ? null : myBound.getCanonicalText(annotated)); } @NotNull @Override public String getInternalCanonicalText() { - return getAnnotationsTextPrefix(true, false, true) + - (myBound == null ? "?" : (myIsExtending ? EXTENDS_PREFIX : SUPER_PREFIX) + myBound.getInternalCanonicalText()); + return getText(true, true, myBound == null ? null : myBound.getInternalCanonicalText()); + } + + private String getText(boolean qualified, boolean annotated, @Nullable String suffix) { + PsiAnnotation[] annotations = getAnnotations(); + if ((!annotated || annotations.length == 0) && suffix == null) return "?"; + + StringBuilder sb = new StringBuilder(); + if (annotated) { + PsiNameHelper.appendAnnotations(sb, annotations, qualified); + } + if (suffix == null) { + sb.append('?'); + } + else { + sb.append(myIsExtending ? EXTENDS_PREFIX : SUPER_PREFIX); + sb.append(suffix); + } + return sb.toString(); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 0de45be17786..77fd0081d161 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -493,6 +493,13 @@ public class PsiImplUtil { return PsiUtil.captureToplevelWildcards(type, expression); } + final PsiElement parent = toplevel.getParent(); + if (parent instanceof PsiExpressionList && + PsiUtil.isLanguageLevel8OrHigher(parent) && + parent.getParent() instanceof PsiCallExpression) { + return PsiUtil.captureToplevelWildcards(type, expression); + } + final PsiType normalized = doNormalizeWildcardByPosition(type, expression, toplevel); LOG.assertTrue(normalized.isValid(), type); if (normalized instanceof PsiClassType && !PsiUtil.isAccessedForWriting(toplevel)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java index 36a725aa3135..369ce919f5a1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java @@ -15,15 +15,18 @@ */ package com.intellij.psi.impl.compiled; +import com.intellij.diagnostic.PluginException; import com.intellij.ide.caches.FileContent; import com.intellij.ide.highlighter.JavaClassFileType; import com.intellij.ide.highlighter.JavaFileType; +import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.lang.ASTNode; import com.intellij.lang.FileASTNode; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.progress.NonCancelableSection; import com.intellij.openapi.progress.ProgressIndicatorProvider; @@ -35,6 +38,7 @@ import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.compiled.ClassFileDecompilers; import com.intellij.psi.impl.JavaPsiImplementationHelper; import com.intellij.psi.impl.PsiFileEx; import com.intellij.psi.impl.java.stubs.PsiClassStub; @@ -324,7 +328,7 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub> setMirror(mirrorTreeElement); } catch (InvalidMirrorException e) { - LOG.error(file.getPath(), e); + LOG.error(file.getPath(), wrapException(e, file)); } finally { section.done(); @@ -337,6 +341,18 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub> return mirrorTreeElement.getPsi(); } + private static Exception wrapException(InvalidMirrorException e, VirtualFile file) { + ClassFileDecompilers.Decompiler decompiler = ClassFileDecompilers.find(file); + if (decompiler instanceof ClassFileDecompilers.Light) { + PluginId pluginId = PluginManagerCore.getPluginByClassName(decompiler.getClass().getName()); + if (pluginId != null) { + return new PluginException(e, pluginId); + } + } + + return e; + } + @Override public PsiFile getDecompiledPsiFile() { return (PsiFile)getMirror(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java index 599f756adbc1..16d971238684 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java @@ -17,8 +17,7 @@ package com.intellij.psi.impl.compiled; import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.openapi.util.NotNullLazyValue; -import com.intellij.openapi.util.NullableLazyValue; -import com.intellij.openapi.util.VolatileNullableLazyValue; +import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.PsiJavaParserFacadeImpl; @@ -28,7 +27,6 @@ import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.TreeElement; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement { @NonNls static final char VARIANCE_NONE = '\0'; @@ -41,18 +39,18 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement private final PsiElement myParent; private final String myTypeText; private final char myVariance; - private final NullableLazyValue<ClsElementImpl> myChild; + private final NotNullLazyValue<Ref<ClsElementImpl>> myChild; private final NotNullLazyValue<PsiType> myCachedType; public ClsTypeElementImpl(@NotNull PsiElement parent, @NotNull String typeText, char variance) { myParent = parent; myTypeText = TypeInfo.internFrequentType(typeText); myVariance = variance; - myChild = new VolatileNullableLazyValue<ClsElementImpl>() { - @Nullable + myChild = new AtomicNotNullLazyValue<Ref<ClsElementImpl>>() { + @NotNull @Override - protected ClsElementImpl compute() { - return calculateChild(); + protected Ref<ClsElementImpl> compute() { + return Ref.create(calculateChild()); } }; myCachedType = new AtomicNotNullLazyValue<PsiType>() { @@ -67,7 +65,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement @Override @NotNull public PsiElement[] getChildren() { - ClsElementImpl child = myChild.getValue(); + ClsElementImpl child = myChild.getValue().get(); return child != null ? new PsiElement[]{child} : PsiElement.EMPTY_ARRAY; } @@ -111,7 +109,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement public void setMirror(@NotNull TreeElement element) throws InvalidMirrorException { setMirrorCheckingType(element, JavaElementType.TYPE); - ClsElementImpl child = myChild.getValue(); + ClsElementImpl child = myChild.getValue().get(); if (child != null) { child.setMirror(element.getFirstChildNode()); } @@ -157,7 +155,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement PsiType result = PsiJavaParserFacadeImpl.getPrimitiveType(myTypeText); if (result != null) return result; - ClsElementImpl childElement = myChild.getValue(); + ClsElementImpl childElement = myChild.getValue().get(); if (childElement instanceof ClsTypeElementImpl) { if (isArray()) { switch (myVariance) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java index a43c02d8a7a4..f304fe250bae 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.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. @@ -30,16 +30,16 @@ import java.util.List; /** * @author max */ -public class PsiClassReferenceType extends PsiClassType { +public class PsiClassReferenceType extends PsiClassType.Stub { @NotNull private final PsiJavaCodeReferenceElement myReference; - public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel langLevel) { - this(reference, langLevel, collectAnnotations(reference)); + public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level) { + this(reference, level, collectAnnotations(reference)); } - public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel langLevel, @NotNull PsiAnnotation[] annotations) { - super(langLevel, annotations); + public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level, @NotNull PsiAnnotation[] annotations) { + super(level, annotations); myReference = reference; } @@ -89,7 +89,7 @@ public class PsiClassReferenceType extends PsiClassType { return resolveGenerics().getElement(); } - private static class DelegatingClassResolveResult implements ClassResolveResult { + private static class DelegatingClassResolveResult implements PsiClassType.ClassResolveResult { private final JavaResolveResult myDelegate; private DelegatingClassResolveResult(@NotNull JavaResolveResult delegate) { @@ -182,19 +182,37 @@ public class PsiClassReferenceType extends PsiClassType { @NotNull @Override public String getPresentableText() { - return getAnnotationsTextPrefix(false, false, true) + PsiNameHelper.getPresentableText(myReference); + String presentableText = PsiNameHelper.getPresentableText(myReference); + PsiAnnotation[] annotations = getAnnotations(); + if (annotations.length == 0) return presentableText; + + StringBuilder sb = new StringBuilder(); + PsiNameHelper.appendAnnotations(sb, annotations, false); + sb.append(presentableText); + return sb.toString(); } @NotNull @Override - public String getCanonicalText() { - return myReference.getCanonicalText(); + public String getCanonicalText(boolean annotated) { + return getText(annotated); } @NotNull @Override public String getInternalCanonicalText() { - return getAnnotationsTextPrefix(true, false, true) + getCanonicalText(); + return getText(true); + } + + private String getText(boolean annotated) { + if (myReference instanceof PsiJavaCodeReferenceElementImpl) { + PsiAnnotation[] annotations = getAnnotations(); + if (!annotated || annotations.length == 0) annotations = null; + return ((PsiJavaCodeReferenceElementImpl)myReference).getCanonicalText(annotated, annotations); + } + else { + return myReference.getCanonicalText(); + } } @NotNull diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java index 9456c29f6ceb..77a45011144d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.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. @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -30,11 +31,12 @@ import java.util.List; /** * @author dsl */ -public class PsiImmediateClassType extends PsiClassType { +public class PsiImmediateClassType extends PsiClassType.Stub { private final PsiClass myClass; private final PsiSubstitutor mySubstitutor; private final PsiManager myManager; private String myCanonicalText; + private String myCanonicalTextAnnotated; private String myPresentableText; private String myInternalCanonicalText; @@ -80,15 +82,15 @@ public class PsiImmediateClassType extends PsiClassType { this(aClass, substitutor, null, PsiAnnotation.EMPTY_ARRAY); } - public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel languageLevel) { - this(aClass, substitutor, languageLevel, PsiAnnotation.EMPTY_ARRAY); + public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel level) { + this(aClass, substitutor, level, PsiAnnotation.EMPTY_ARRAY); } public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, - @Nullable LanguageLevel languageLevel, - @NotNull PsiAnnotation[] annotations) { - super(languageLevel, annotations); + @Nullable LanguageLevel level, + @NotNull PsiAnnotation... annotations) { + super(level, annotations); myClass = aClass; myManager = aClass.getManager(); mySubstitutor = substitutor; @@ -138,112 +140,119 @@ public class PsiImmediateClassType extends PsiClassType { @Override public String getPresentableText() { if (myPresentableText == null) { - StringBuilder buffer = new StringBuilder(); - buildText(myClass, mySubstitutor, buffer, false, false); - myPresentableText = buffer.toString(); + myPresentableText = getText(TextType.PRESENTABLE, true); } return myPresentableText; } @NotNull @Override - public String getCanonicalText() { - if (myCanonicalText == null) { - assert mySubstitutor.isValid(); - StringBuilder buffer = new StringBuilder(); - buildText(myClass, mySubstitutor, buffer, true, false); - myCanonicalText = buffer.toString(); + public String getCanonicalText(boolean annotated) { + String cached = annotated ? myCanonicalTextAnnotated : myCanonicalText; + if (cached == null) { + cached = getText(TextType.CANONICAL, annotated); + if (annotated) myCanonicalTextAnnotated = cached; + else myCanonicalText = cached; } - return myCanonicalText; + return cached; } @NotNull @Override public String getInternalCanonicalText() { if (myInternalCanonicalText == null) { - StringBuilder buffer = new StringBuilder(); - buildText(myClass, mySubstitutor, buffer, true, true); - myInternalCanonicalText = buffer.toString(); + myInternalCanonicalText = getText(TextType.INT_CANONICAL, true); } return myInternalCanonicalText; } + private enum TextType { PRESENTABLE, CANONICAL, INT_CANONICAL } + + private String getText(@NotNull TextType textType, boolean annotated) { + assert mySubstitutor.isValid(); + StringBuilder buffer = new StringBuilder(); + buildText(myClass, mySubstitutor, buffer, textType, annotated); + return buffer.toString(); + } + private void buildText(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @NotNull StringBuilder buffer, - boolean canonical, - boolean internal) { + @NotNull TextType textType, + boolean annotated) { if (aClass instanceof PsiAnonymousClass) { - ClassResolveResult baseResolveResult = ((PsiAnonymousClass) aClass).getBaseClassType().resolveGenerics(); + ClassResolveResult baseResolveResult = ((PsiAnonymousClass)aClass).getBaseClassType().resolveGenerics(); PsiClass baseClass = baseResolveResult.getElement(); - PsiSubstitutor baseSub = baseResolveResult.getSubstitutor(); if (baseClass != null) { - buildText(baseClass, baseSub, buffer, canonical, internal); + buildText(baseClass, baseResolveResult.getSubstitutor(), buffer, textType, false); } return; } - if (canonical == internal) { - buffer.append(getAnnotationsTextPrefix(internal, false, true)); - } + boolean qualified = textType != TextType.PRESENTABLE; PsiClass enclosingClass = null; if (!aClass.hasModifierProperty(PsiModifier.STATIC)) { - final PsiElement parent = aClass.getParent(); + PsiElement parent = aClass.getParent(); if (parent instanceof PsiClass && !(parent instanceof PsiAnonymousClass)) { enclosingClass = (PsiClass)parent; } } if (enclosingClass != null) { - buildText(enclosingClass, substitutor, buffer, canonical, false); + buildText(enclosingClass, substitutor, buffer, textType, false); buffer.append('.'); - buffer.append(aClass.getName()); } - else { - final String name; - if (!canonical) { - name = aClass.getName(); - } - else { - final String qualifiedName = aClass.getQualifiedName(); - if (qualifiedName == null) { - name = aClass.getName(); - } - else { - name = qualifiedName; + else if (qualified) { + String fqn = aClass.getQualifiedName(); + if (fqn != null) { + String prefix = StringUtil.getPackageName(fqn); + if (!StringUtil.isEmpty(prefix)) { + buffer.append(prefix); + buffer.append('.'); } } - buffer.append(name); } + if (annotated) { + PsiNameHelper.appendAnnotations(buffer, getAnnotations(), qualified); + } + + buffer.append(aClass.getName()); + PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); if (typeParameters.length > 0) { - StringBuilder pineBuffer = new StringBuilder(); - pineBuffer.append('<'); + int pos = buffer.length(); + buffer.append('<'); + for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; PsiUtilCore.ensureValid(typeParameter); - if (i > 0) pineBuffer.append(','); - final PsiType substitutionResult = substitutor.substitute(typeParameter); + + if (i > 0) { + buffer.append(','); + if (textType == TextType.PRESENTABLE) buffer.append(' '); + } + + PsiType substitutionResult = substitutor.substitute(typeParameter); if (substitutionResult == null) { - pineBuffer = null; + buffer.setLength(pos); + pos = -1; break; } PsiUtil.ensureValidType(substitutionResult); - if (canonical) { - if (internal) { - pineBuffer.append(substitutionResult.getInternalCanonicalText()); - } - else { - pineBuffer.append(substitutionResult.getCanonicalText()); - } + + if (textType == TextType.PRESENTABLE) { + buffer.append(substitutionResult.getPresentableText()); + } + else if (textType == TextType.CANONICAL) { + buffer.append(substitutionResult.getCanonicalText(annotated)); } else { - pineBuffer.append(substitutionResult.getPresentableText()); + buffer.append(substitutionResult.getInternalCanonicalText()); } } - if (pineBuffer != null) { - buffer.append(pineBuffer); + + if (pos >= 0) { buffer.append('>'); } } @@ -265,7 +274,6 @@ public class PsiImmediateClassType extends PsiClassType { return false; } return equals(patternType); - } @Override @@ -277,14 +285,12 @@ public class PsiImmediateClassType extends PsiClassType { @Override @NotNull public LanguageLevel getLanguageLevel() { - if (myLanguageLevel != null) return myLanguageLevel; - return PsiUtil.getLanguageLevel(myClass); + return myLanguageLevel != null ? myLanguageLevel : PsiUtil.getLanguageLevel(myClass); } @NotNull @Override - public PsiClassType setLanguageLevel(@NotNull final LanguageLevel languageLevel) { - if (languageLevel.equals(myLanguageLevel)) return this; - return new PsiImmediateClassType(myClass, mySubstitutor, languageLevel,getAnnotations()); + public PsiClassType setLanguageLevel(@NotNull LanguageLevel level) { + return level.equals(myLanguageLevel) ? this : new PsiImmediateClassType(myClass, mySubstitutor, level, getAnnotations()); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index 396b750c8c2a..5ee1243b09ce 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.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. @@ -49,6 +49,7 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.List; public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement implements PsiJavaCodeReferenceElement, SourceJavaCodeReference { @@ -255,36 +256,47 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme @Override @NotNull public String getCanonicalText() { + return getCanonicalText(false, null); + } + + @NotNull + public String getCanonicalText(boolean annotated, @Nullable PsiAnnotation[] annotations) { switch (getKind()) { case CLASS_NAME_KIND: case CLASS_OR_PACKAGE_NAME_KIND: case CLASS_IN_QUALIFIED_NEW_KIND: final PsiElement target = resolve(); if (target instanceof PsiClass) { - final PsiClass aClass = (PsiClass)target; - String name = aClass.getQualifiedName(); - if (name == null) { - name = aClass.getName(); //? + PsiClass aClass = (PsiClass)target; + StringBuilder buffer = new StringBuilder(); + + PsiElement qualifier = getQualifier(); + String prefix = null; + if (qualifier instanceof PsiJavaCodeReferenceElementImpl) { + prefix = ((PsiJavaCodeReferenceElementImpl)qualifier).getCanonicalText(annotated, null); } - final PsiType[] types = getTypeParameters(); - if (types.length == 0) { - final PsiElement qualifier = getQualifier(); - if (qualifier instanceof PsiJavaCodeReferenceElement) { - return StringUtil.getQualifiedName(((PsiJavaCodeReferenceElement)qualifier).getCanonicalText(), aClass.getName()); + else { + String fqn = aClass.getQualifiedName(); + if (fqn != null) { + prefix = StringUtil.getPackageName(fqn); } - return name; } - final StringBuilder buf = new StringBuilder(); - buf.append(name); - buf.append('<'); - for (int i = 0; i < types.length; i++) { - if (i > 0) buf.append(','); - buf.append(types[i].getCanonicalText()); + if (!StringUtil.isEmpty(prefix)) { + buffer.append(prefix); + buffer.append('.'); } - buf.append('>'); - return buf.toString(); + if (annotated) { + List<PsiAnnotation> list = annotations != null ? Arrays.asList(annotations) : getAnnotations(); + PsiNameHelper.appendAnnotations(buffer, list, true); + } + + buffer.append(aClass.getName()); + + PsiNameHelper.appendTypeArgs(buffer, getTypeParameters(), true, annotated); + + return buffer.toString(); } else if (target instanceof PsiPackage) { return ((PsiPackage)target).getQualifiedName(); @@ -293,6 +305,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme LOG.assertTrue(target == null, target); return getNormalizedText(); } + case PACKAGE_NAME_KIND: case CLASS_FQ_NAME_KIND: case CLASS_FQ_OR_PACKAGE_NAME_KIND: @@ -327,7 +340,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme if (incompleteCode && result.length == 0 && kind != CLASS_FQ_NAME_KIND && kind != CLASS_FQ_OR_PACKAGE_NAME_KIND) { VariableResolverProcessor processor = new VariableResolverProcessor(referenceElement, containingFile); - PsiScopesUtil.resolveAndWalk(processor, referenceElement, null, incompleteCode); + PsiScopesUtil.resolveAndWalk(processor, referenceElement, null, true); result = processor.getResult(); if (result.length == 0 && kind == CLASS_NAME_KIND) { result = referenceElement.resolve(PACKAGE_NAME_KIND, containingFile); @@ -457,16 +470,16 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme case CLASS_FQ_OR_PACKAGE_NAME_KIND: case CLASS_OR_PACKAGE_NAME_KIND: { int classKind = kind == CLASS_OR_PACKAGE_NAME_KIND ? CLASS_NAME_KIND : CLASS_FQ_NAME_KIND; - JavaResolveResult[] result = resolve(classKind,containingFile); + JavaResolveResult[] result = resolve(classKind, containingFile); if (result.length == 1 && !result[0].isAccessible()) { - JavaResolveResult[] packageResult = resolve(PACKAGE_NAME_KIND,containingFile); + JavaResolveResult[] packageResult = resolve(PACKAGE_NAME_KIND, containingFile); if (packageResult.length != 0) { result = packageResult; } } else if (result.length == 0) { - result = resolve(PACKAGE_NAME_KIND,containingFile); + result = resolve(PACKAGE_NAME_KIND, containingFile); } return result; @@ -607,7 +620,12 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme for (PsiAnnotation annotation : annotations) { if (annotation.getParent() != newParent) { - newParent.addAfter(annotation, anchor); + if (anchor != null) { + newParent.addAfter(annotation, anchor); + } + else { + newParent.add(annotation); + } annotation.delete(); } } @@ -935,7 +953,6 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme final PsiReferenceParameterList parameterList = getParameterList(); if (parameterList == null) return PsiType.EMPTY_ARRAY; return parameterList.getTypeArguments(); - } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java index 5b76439ef406..20db589bef5c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java @@ -225,15 +225,21 @@ public class JavaResolveUtil { return true; } - public static void substituteResults(@NotNull PsiJavaCodeReferenceElement ref, @NotNull JavaResolveResult[] result) { + public static void substituteResults(final @NotNull PsiJavaCodeReferenceElement ref, @NotNull JavaResolveResult[] result) { if (result.length > 0 && result[0].getElement() instanceof PsiClass) { - PsiType[] parameters = ref.getTypeParameters(); for (int i = 0; i < result.length; i++) { - CandidateInfo resolveResult = (CandidateInfo)result[i]; - PsiElement resultElement = resolveResult.getElement(); + final CandidateInfo resolveResult = (CandidateInfo)result[i]; + final PsiElement resultElement = resolveResult.getElement(); if (resultElement instanceof PsiClass && ((PsiClass)resultElement).hasTypeParameters()) { - PsiSubstitutor substitutor = resolveResult.getSubstitutor().putAll((PsiClass)resultElement, parameters); - result[i] = new CandidateInfo(resolveResult, substitutor); + PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + result[i] = new CandidateInfo(resolveResult, substitutor) { + @NotNull + @Override + public PsiSubstitutor getSubstitutor() { + final PsiType[] parameters = ref.getTypeParameters(); + return super.getSubstitutor().putAll((PsiClass)resultElement, parameters); + } + }; } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java index a52ea73a18d5..b4b188c772cc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java @@ -18,7 +18,6 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeEqualityConstraint; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; @@ -102,7 +101,7 @@ public class FunctionalInterfaceParameterizationUtil { return null; } - final PsiSubstitutor substitutor = session.resolveDependencies(session.getInferenceVariables()); + final PsiSubstitutor substitutor = session.retrieveNonPrimitiveEqualsBounds(session.getInferenceVariables()); final PsiType[] newTypeParameters = new PsiType[parameters.length]; for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; @@ -119,14 +118,10 @@ public class FunctionalInterfaceParameterizationUtil { return null; } - if (!TypeConversionUtil.containsWildcards(parameterization)) { + if (!TypeConversionUtil.containsWildcards(parameterization) && psiClassType.isAssignableFrom(parameterization)) { return parameterization; } - if (!psiClassType.isAssignableFrom(parameterization)) { - return null; - } - return getNonWildcardParameterization((PsiClassType)psiClassType); } return null; @@ -169,27 +164,32 @@ public class FunctionalInterfaceParameterizationUtil { for (int i = 0; i < parameters.length; i++) { PsiType paramType = parameters[i]; if (paramType instanceof PsiWildcardType) { - final PsiClassType[] extendsListTypes = typeParameters[i].getExtendsListTypes(); - final PsiClassType Bi = extendsListTypes.length > 0 ? extendsListTypes[0] - : PsiType.getJavaLangObject(psiClass.getManager(), - GlobalSearchScope.allScope(psiClass.getProject())); - if (PsiPolyExpressionUtil.mentionsTypeParameters(Bi, typeParametersSet)) { - return null; + final PsiType bound = GenericsUtil.eliminateWildcards(((PsiWildcardType)paramType).getBound(), false); + if (((PsiWildcardType)paramType).isSuper()) { + newParameters[i] = bound; } - - final PsiType bound = ((PsiWildcardType)paramType).getBound(); - if (bound == null) { - newParameters[i] = Bi; - } else if (((PsiWildcardType)paramType).isExtends()){ - newParameters[i] = GenericsUtil.getGreatestLowerBound(Bi, GenericsUtil.eliminateWildcards(bound, false)); - } else { - newParameters[i] = GenericsUtil.eliminateWildcards(bound, false); + else { + newParameters[i] = bound != null ? bound : PsiType.getJavaLangObject(psiClass.getManager(), psiClassType.getResolveScope()); + for (PsiClassType paramBound : typeParameters[i].getExtendsListTypes()) { + if (!PsiPolyExpressionUtil.mentionsTypeParameters(paramBound, typeParametersSet)) { + newParameters[i] = GenericsUtil.getGreatestLowerBound(paramBound, newParameters[i]); + } + } } } else { newParameters[i] = paramType; } } - return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, newParameters); + + if (!isWellFormed(psiClass, typeParameters, newParameters)) { + return null; + } + + final PsiClassType parameterization = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, newParameters); + if (!psiClassType.isAssignableFrom(parameterization)) { + return null; + } + return parameterization; } return null; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java index cc666815c2d2..f30c7ae6382c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java @@ -110,18 +110,6 @@ public class InferenceIncorporationPhase { } } } - - //todo no such a rule in spec?! - for (PsiType lowerBound : lowerBounds) { - if (mySession.isProperType(lowerBound)) { - final PsiSubstitutor substitutor = PsiSubstitutor.EMPTY.put(inferenceVariable.getParameter(), lowerBound); - for (PsiType upperBound : upperBounds) { - if (!mySession.isProperType(upperBound)) { - addConstraint(new StrictSubtypingConstraint(substitutor.substitute(upperBound), lowerBound)); - } - } - } - } } for (Pair<PsiTypeParameter[], PsiClassType> capture : myCaptures) { @@ -389,21 +377,4 @@ public class InferenceIncorporationPhase { } } } - - public PsiSubstitutor checkIncorporated(PsiSubstitutor substitutor, Collection<InferenceVariable> variables) { - for (InferenceVariable variable : variables) { //todo equals bounds? - for (PsiType lowerBound : variable.getBounds(InferenceBound.LOWER)) { - lowerBound = substitutor.substitute(lowerBound); - if (mySession.isProperType(lowerBound)) { - for (PsiType upperBound : variable.getBounds(InferenceBound.UPPER)) { - upperBound = substitutor.substitute(upperBound); - if (mySession.isProperType(upperBound) && !TypeConversionUtil.isAssignable(upperBound, lowerBound)) { - return null; - } - } - } - } - } - return substitutor; - } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index abde4616fe77..53911011bc17 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -20,15 +20,8 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.resolve.graphInference.constraints.*; import com.intellij.psi.infos.MethodCandidateInfo; -import com.intellij.psi.scope.MethodProcessorSetupFailedException; -import com.intellij.psi.scope.PsiConflictResolver; -import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver; -import com.intellij.psi.scope.processor.MethodCandidatesProcessor; -import com.intellij.psi.scope.processor.MethodResolverProcessor; -import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; @@ -174,7 +167,8 @@ public class InferenceSession { return true; } - private static PsiType getParameterType(PsiParameter[] parameters, PsiExpression[] args, int i, PsiSubstitutor substitutor) { + private static PsiType getParameterType(PsiParameter[] parameters, PsiExpression[] args, int i, @Nullable PsiSubstitutor substitutor) { + if (substitutor == null) return null; PsiType parameterType = substitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType()); if (parameterType instanceof PsiEllipsisType) { final PsiExpression arg = args[i]; @@ -213,7 +207,7 @@ public class InferenceSession { PsiMethod parentMethod) { if (!repeatInferencePhases(true)) { //inferred result would be checked as candidate won't be applicable - return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false); + return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor); } if (parentMethod != null) { @@ -299,17 +293,17 @@ public class InferenceSession { } } } else { - return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false); + return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor); } return prepareSubstitution(); } - public PsiSubstitutor resolveDependencies(Collection<InferenceVariable> variables) { + public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) { PsiSubstitutor substitutor = mySiteSubstitutor; for (InferenceVariable variable : variables) { final PsiType equalsBound = getEqualsBound(variable, substitutor); - if (equalsBound != PsiType.NULL) { + if (!(equalsBound instanceof PsiPrimitiveType)) { substitutor = substitutor.put(variable.getParameter(), equalsBound); } } @@ -340,9 +334,13 @@ public class InferenceSession { return false; } - public void initBounds(PsiTypeParameter... typeParameters) { + public boolean initBounds(PsiTypeParameter... typeParameters) { + boolean sameMethodCall = false; for (PsiTypeParameter parameter : typeParameters) { - if (myInferenceVariables.containsKey(parameter)) continue; + if (myInferenceVariables.containsKey(parameter)) { + sameMethodCall = true; + continue; + } InferenceVariable variable = new InferenceVariable(parameter); boolean added = false; final PsiClassType[] extendsListTypes = parameter.getExtendsListTypes(); @@ -359,29 +357,19 @@ public class InferenceSession { } myInferenceVariables.put(parameter, variable); } - } - - public void addCapturedVariable(PsiTypeParameter param) { - initBounds(param); + return sameMethodCall; } private void initReturnTypeConstraint(PsiMethod method, final PsiCallExpression context) { - if (PsiPolyExpressionUtil.isMethodCallPolyExpression(context, method) || - context instanceof PsiNewExpression && PsiDiamondType.ourDiamondGuard.currentStack().contains(context)) { + if (PsiPolyExpressionUtil.isMethodCallPolyExpression(context, method)) { PsiType returnType = method.getReturnType(); if (!PsiType.VOID.equals(returnType) && returnType != null) { - returnType = PsiImplUtil.normalizeWildcardTypeByPosition(returnType, context); PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context); if (targetType == null) { - targetType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(context, false, new Computable<PsiType>() { - @Override - public PsiType compute() { - return getTargetType(context); - } - }); + targetType = getTargetType(context); } if (targetType != null) { - registerConstraints(returnType, targetType); + registerConstraints(PsiUtil.isRawSubstitutor(method, mySiteSubstitutor) ? returnType : mySiteSubstitutor.substitute(returnType), targetType); } } } @@ -397,7 +385,7 @@ public class InferenceSession { public void registerConstraints(PsiType returnType, PsiType targetType) { final InferenceVariable inferenceVariable = shouldResolveAndInstantiate(returnType, targetType); if (inferenceVariable != null) { - final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor, true); + final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor); myConstraints.add(new TypeCompatibilityConstraint(targetType, PsiUtil.captureToplevelWildcards(substitutor.substitute(inferenceVariable.getParameter()), myContext))); } else { @@ -412,7 +400,7 @@ public class InferenceSession { PsiTypeParameter[] copy = new PsiTypeParameter[typeParameters.length]; for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; - copy[i] = elementFactory.createTypeParameterFromText(typeParameter.getName(), null); + copy[i] = elementFactory.createTypeParameterFromText("rCopy" + typeParameter.getName(), null); initBounds(copy[i]); subst = subst.put(typeParameter, elementFactory.createType(copy[i])); } @@ -495,7 +483,7 @@ public class InferenceSession { return false; } - private PsiType getTargetType(final PsiExpression context) { + private static PsiType getTargetType(final PsiExpression context) { final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent()); if (parent instanceof PsiExpressionList) { PsiElement gParent = parent.getParent(); @@ -505,28 +493,8 @@ public class InferenceSession { if (gParent instanceof PsiCallExpression) { final PsiExpressionList argumentList = ((PsiCallExpression)gParent).getArgumentList(); if (argumentList != null) { - final Pair<PsiMethod, PsiSubstitutor> pair = MethodCandidateInfo.getCurrentMethod(argumentList); - final PsiFile placeFile = context.getContainingFile(); - final JavaMethodsConflictResolver conflictResolver = new JavaMethodsConflictResolver(argumentList, PsiUtil.getLanguageLevel(placeFile)){ - @Override - protected PsiType[] getArgumentTypes() { - return InferenceSession.getArgumentTypes(argumentList, context); - } - }; - final MethodCandidatesProcessor processor = new MethodResolverProcessor((PsiCallExpression)gParent, placeFile, new PsiConflictResolver[]{conflictResolver}) { - @Override - protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) { - return getArgumentTypes(argumentList, context); - } - }; - try { - PsiScopesUtil.setupAndRunProcessor(processor, (PsiCallExpression)gParent, false); - } - catch (MethodProcessorSetupFailedException e) { - return null; - } - final JavaResolveResult[] results = processor.getResult(); - return results.length == 1 ? getTypeByMethod(context, argumentList, pair, results[0], results[0].getElement()) : null; + final JavaResolveResult result = ((PsiCallExpression)gParent).resolveMethodGenerics(); + return getTypeByMethod(context, argumentList, result, result.getElement()); } } } else if (parent instanceof PsiConditionalExpression) { @@ -546,30 +514,9 @@ public class InferenceSession { return null; } - private static PsiType[] getArgumentTypes(PsiExpressionList argumentList, PsiExpression context) { - if (argumentList != null) { - final PsiExpression[] expressions = argumentList.getExpressions(); - final int idx = LambdaUtil.getLambdaIdx(argumentList, context); - final PsiType[] types = PsiType.createArray(expressions.length); - for (int i = 0; i < expressions.length; i++) { - if (i != idx) { - types[i] = expressions[i].getType(); - } - else { - types[i] = PsiType.NULL; - } - } - return types; - } - else { - return null; - } - } - - private PsiType getTypeByMethod(PsiExpression context, - PsiExpressionList argumentList, - Pair<PsiMethod, PsiSubstitutor> pair, - JavaResolveResult result, PsiElement parentMethod) { + private static PsiType getTypeByMethod(PsiExpression context, + PsiExpressionList argumentList, + final JavaResolveResult result, PsiElement parentMethod) { if (parentMethod instanceof PsiMethod) { final PsiParameter[] parameters = ((PsiMethod)parentMethod).getParameterList().getParameters(); if (parameters.length == 0) return null; @@ -581,23 +528,13 @@ public class InferenceSession { } final int i = ArrayUtilRt.find(args, arg); if (i < 0) return null; - final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(argumentList, PsiCallExpression.class); - if (callExpression != null && callExpression.getTypeArguments().length > 0) { - return getParameterType(parameters, args, i, ((MethodCandidateInfo)result).typeArgumentsSubstitutor()); - } - final PsiType parameterType = getParameterType(parameters, args, i, pair != null ? pair.second : PsiSubstitutor.EMPTY); - args[i] = null; - final PsiTypeParameter[] typeParameters = ((PsiMethod)parentMethod).getTypeParameters(); - final InferenceSession session = new InferenceSession(typeParameters, ((MethodCandidateInfo)result).getSiteSubstitutor(), myManager, argumentList); - session.initExpressionConstraints(parameters, args, argumentList, (PsiMethod)parentMethod); - if (session.tryToInfer(parameters, args, callExpression, (PsiMethod)parentMethod) != null) { - return null; - } - final Collection<PsiTypeParameter> params = session.getTypeParams(); - initBounds(params.toArray(new PsiTypeParameter[params.size()])); - liftBounds(session.getInferenceVariables()); - final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).getSiteSubstitutor(); - return substitutor.substitute(parameterType); + return getParameterType(parameters, args, i, PsiResolveHelper.ourGraphGuard.doPreventingRecursion(argumentList.getParent(), false, + new Computable<PsiSubstitutor>() { + @Override + public PsiSubstitutor compute() { + return result.getSubstitutor(); + } + })); } return null; } @@ -720,7 +657,7 @@ public class InferenceSession { while (!allVars.isEmpty()) { final List<InferenceVariable> vars = InferenceVariablesOrder.resolveOrder(allVars, this); if (!myIncorporationPhase.hasCaptureConstraints(vars)) { - final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor, true); + final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor); if (firstSubstitutor != null) { substitutor = firstSubstitutor; allVars.removeAll(vars); @@ -731,7 +668,7 @@ public class InferenceSession { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); for (InferenceVariable var : vars) { final PsiTypeParameter parameter = var.getParameter(); - final PsiTypeParameter copy = elementFactory.createTypeParameterFromText(parameter.getName(), null); + final PsiTypeParameter copy = elementFactory.createTypeParameterFromText("z" + parameter.getName(), null); final PsiType lub = getLowerBound(var, substitutor); final PsiType glb = getUpperBound(var, substitutor); final InferenceVariable zVariable = new InferenceVariable(copy); @@ -744,6 +681,8 @@ public class InferenceSession { zVariable.addBound(lub, InferenceBound.LOWER); } myInferenceVariables.put(copy, zVariable); + allVars.add(zVariable); + var.addBound(elementFactory.createType(copy), InferenceBound.EQ); } myIncorporationPhase.forgetCaptures(vars); if (!myIncorporationPhase.incorporate()) { @@ -762,7 +701,7 @@ public class InferenceSession { }, substitutor); } - private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor, boolean checkResult) { + private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor) { for (InferenceVariable var : vars) { LOG.assertTrue(var.getInstantiation() == PsiType.NULL); final PsiTypeParameter typeParameter = var.getParameter(); @@ -781,7 +720,7 @@ public class InferenceSession { } } - return checkResult ? myIncorporationPhase.checkIncorporated(substitutor, vars) : substitutor; + return substitutor; } private PsiType getUpperBound(InferenceVariable var, PsiSubstitutor substitutor) { @@ -872,7 +811,7 @@ public class InferenceSession { } //resolve input variables - PsiSubstitutor substitutor = resolveSubset(varsToResolve, mySiteSubstitutor, true); + PsiSubstitutor substitutor = resolveSubset(varsToResolve, mySiteSubstitutor); if (substitutor == null) { return false; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java index a67b64eea669..a629175b9d48 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java @@ -48,17 +48,6 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai if (!PsiPolyExpressionUtil.isPolyExpression(myExpression)) { return true; } - if (myExpression instanceof PsiCallExpression) { - final PsiExpressionList argumentList = ((PsiCallExpression)myExpression).getArgumentList(); - if (argumentList != null) { - for (PsiExpression expression : argumentList.getExpressions()) { - if (PsiPolyExpressionUtil.isPolyExpression(expression)) { - //todo additional constraints [JDK-8033488] - } - } - } - return true; - } if (myExpression instanceof PsiParenthesizedExpression) { constraints.add(new CheckedExceptionCompatibilityConstraint(((PsiParenthesizedExpression)myExpression).getExpression(), myT)); return true; @@ -122,7 +111,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai final PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor(); final PsiMethod method; if (((PsiMethodReferenceExpression)myExpression).isExact()) { - final PsiElement resolve = ((PsiMethodReferenceExpression)myExpression).resolve(); + final PsiElement resolve = ((PsiMethodReferenceExpression)myExpression).getPotentiallyApplicableMember(); if (resolve instanceof PsiMethod) { method = (PsiMethod)resolve; } else { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index 30628e36beb6..ebcbda6a2926 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -21,10 +21,13 @@ import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl; import com.intellij.psi.infos.MethodCandidateInfo; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -99,22 +102,51 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm if (typeParams != null) { - for (PsiTypeParameter typeParam : typeParams) { - session.addCapturedVariable(typeParam); - } + final HashSet<PsiTypeParameter> oldBounds = new HashSet<PsiTypeParameter>(session.getTypeParams()); + final boolean sameMethodCall = session.initBounds(typeParams); PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; + final HashSet<InferenceVariable> variables = new HashSet<InferenceVariable>(); + session.collectDependencies(returnType, variables); + final PsiTypeParameter[] params = new PsiTypeParameter[typeParams.length]; + for (int i = 0; i < typeParams.length; i++) { + if (variables.contains(session.getInferenceVariable(typeParams[i]))) { + params[i] = JavaPsiFacade.getElementFactory(myExpression.getProject()).createTypeParameterFromText("copyOf" + myExpression.hashCode() + typeParams[i].getName(), null); + substitutor = substitutor.put(typeParams[i], JavaPsiFacade.getElementFactory(myExpression.getProject()).createType(params[i])); + } + else { + params[i] = typeParams[i]; + } + } + final PsiSubstitutor siteSubstitutor = resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor() + ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : PsiSubstitutor.EMPTY; + for (PsiTypeParameter typeParameter : siteSubstitutor.getSubstitutionMap().keySet()) { + substitutor = substitutor.put(typeParameter, substitutor.substitute(siteSubstitutor.substitute(typeParameter))); + } + + final Collection<PsiTypeParameter> params1 = session.getTypeParams(); + final InferenceSession callSession = new InferenceSession(params1.toArray(new PsiTypeParameter[params1.size()]), substitutor, myExpression.getManager(), myExpression); + callSession.initBounds(params); if (method != null) { - //typeParams are already included - final Collection<PsiTypeParameter> params = session.getTypeParams(); - InferenceSession callSession = new InferenceSession(params.toArray(new PsiTypeParameter[params.size()]), resolveResult instanceof MethodCandidateInfo ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() - : PsiSubstitutor.EMPTY, myExpression.getManager(), myExpression); final PsiExpression[] args = argumentList.getExpressions(); final PsiParameter[] parameters = method.getParameterList().getParameters(); callSession.initExpressionConstraints(parameters, args, myExpression, method); - callSession.registerConstraints(returnType, myT); - if (callSession.repeatInferencePhases(true)) { - session.liftBounds(callSession.getInferenceVariables()); + } + final boolean accepted = callSession.repeatInferencePhases(true); + if (!accepted) { + //todo return false; + } + callSession.registerConstraints(method != null && !PsiUtil.isRawSubstitutor(method, siteSubstitutor) ? siteSubstitutor.substitute(returnType) : returnType, substitutor.substitute(returnType)); + if (callSession.repeatInferencePhases(true)) { + final Collection<InferenceVariable> inferenceVariables = callSession.getInferenceVariables(); + if (sameMethodCall) { + for (Iterator<InferenceVariable> iterator = inferenceVariables.iterator(); iterator.hasNext(); ) { + InferenceVariable variable = iterator.next(); + if (oldBounds.contains(variable.getParameter())) { + iterator.remove(); + } + } } + session.liftBounds(inferenceVariables); } final PsiType capturedReturnType = myExpression instanceof PsiMethodCallExpression ? PsiMethodCallExpressionImpl.captureReturnType((PsiMethodCallExpression)myExpression, method, returnType, substitutor) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java index 7e2443a8232f..cbb1db809c4a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java @@ -109,6 +109,11 @@ public class TypeEqualityConstraint implements ConstraintFormula { return true; } + if (myT instanceof PsiCapturedWildcardType && myS instanceof PsiCapturedWildcardType) { + return new TypeEqualityConstraint(((PsiCapturedWildcardType)myT).getWildcard(), + ((PsiCapturedWildcardType)myS).getWildcard()).reduce(session, constraints); + } + return false; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java index 58c29706c1a3..18ff2d110ad9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java @@ -25,7 +25,6 @@ import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiUtil; import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -55,18 +54,19 @@ public class JavaSharedImplUtil { return type; } + // collects annotations bound to C-style arrays private static List<PsiAnnotation[]> collectAnnotations(PsiElement anchor, PsiAnnotation stopAt) { - List<PsiAnnotation[]> annotations = new SmartList<PsiAnnotation[]>(); + List<PsiAnnotation[]> annotations = ContainerUtil.newSmartList(); List<PsiAnnotation> current = null; - boolean stop = false; + boolean found = (stopAt == null), stop = false; for (PsiElement child = anchor.getNextSibling(); child != null; child = child.getNextSibling()) { if (child instanceof PsiComment || child instanceof PsiWhiteSpace) continue; if (child instanceof PsiAnnotation) { - if (current == null) current = new SmartList<PsiAnnotation>(); + if (current == null) current = ContainerUtil.newSmartList(); current.add((PsiAnnotation)child); - if (child == stopAt) stop = true; + if (child == stopAt) found = stop = true; continue; } @@ -80,8 +80,8 @@ public class JavaSharedImplUtil { } } - // stop == true means annotation is misplaced - return stop ? null : annotations; + // annotation is misplaced (either located before the anchor or has no following brackets) + return !found || stop ? null : annotations; } public static void normalizeBrackets(@NotNull PsiVariable variable) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaTreeGenerator.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaTreeGenerator.java index f6ba9fdf5af4..918d7fed7237 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaTreeGenerator.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaTreeGenerator.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. @@ -131,7 +131,7 @@ public class JavaTreeGenerator implements TreeGenerator { type = PsiType.getJavaLangObject(manager, GlobalSearchScope.projectScope(manager.getProject())); } - String text = type.getPresentableText(); + String text = type.getCanonicalText(true); PsiJavaParserFacade parserFacade = JavaPsiFacade.getInstance(original.getProject()).getParserFacade(); PsiTypeElement element = parserFacade.createTypeElementFromText(text, original); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ExpressionPsiElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ExpressionPsiElement.java index cf40d04ca427..1d8693efc55c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ExpressionPsiElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ExpressionPsiElement.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. @@ -38,7 +38,8 @@ public class ExpressionPsiElement extends CompositePsiElement { @Override public void replaceChildInternal(@NotNull ASTNode child, @NotNull TreeElement newElement) { - if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) { + if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType()) && + ElementType.EXPRESSION_BIT_SET.contains(newElement.getElementType())) { boolean needParenth = ReplaceExpressionUtil.isNeedParenthesis(child, newElement); if (needParenth) { newElement = SourceUtil.addParenthToReplacedChild(JavaElementType.PARENTH_EXPRESSION, newElement, getManager()); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index fdd02e86ebb3..084be88d7428 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -499,6 +499,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final PsiClass pClass = pResult.getElement(); final PsiSubstitutor receiverSubstitutor = pClass != null ? TypeConversionUtil.getClassSubstitutor(containingClass, pClass, pResult.getSubstitutor()) : null; if (receiverSubstitutor != null) { + if (!method.hasTypeParameters() && signature.getParameterTypes().length == 1) return receiverSubstitutor; psiSubstitutor = receiverSubstitutor; } } @@ -638,20 +639,26 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase } } - checkSpecifics(firstCandidates, - varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); - - checkSpecifics(secondCandidates, - varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); - if (myQualifierResolveResult.isReferenceTypeQualified() && getReferenceNameElement() instanceof PsiIdentifier) { //If the first search produces a static method, and no non-static method is applicable for the second search, then the result of the first search is the compile-time declaration. - filterStaticCorrectCandidates(firstCandidates, true); + CandidateInfo candidateInfo = filterStaticCorrectCandidates(firstCandidates, secondCandidates, true); + if (candidateInfo != null) { + return candidateInfo; + } //If the second search produces a non-static method, and no static method is applicable for the first search, then the result of the second search is the compile-time declaration. - filterStaticCorrectCandidates(secondCandidates, false); + candidateInfo = filterStaticCorrectCandidates(secondCandidates, firstCandidates, false); + if (candidateInfo != null) { + return candidateInfo; + } } + checkSpecifics(firstCandidates, + varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); + + checkSpecifics(secondCandidates, + varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); + final int acceptedCount = firstCandidates.size() + secondCandidates.size(); if (acceptedCount == 1) { return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0); @@ -684,17 +691,29 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase /** * 15.13.1 */ - private void filterStaticCorrectCandidates(List<CandidateInfo> firstCandidates, + private CandidateInfo filterStaticCorrectCandidates(List<CandidateInfo> firstCandidates, + List<CandidateInfo> secondCandidates, boolean shouldBeStatic) { - for (Iterator<CandidateInfo> iterator = firstCandidates.iterator(); iterator.hasNext(); ) { - final PsiElement element = iterator.next().getElement(); + if (firstCandidates.size() == 1) { + final CandidateInfo candidateInfo = firstCandidates.get(0); + final PsiElement element = candidateInfo.getElement(); if (element instanceof PsiMethod) { final boolean isStatic = ((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC); - if (shouldBeStatic && !isStatic || !shouldBeStatic && isStatic) { - iterator.remove(); + if (shouldBeStatic && isStatic || !shouldBeStatic && !isStatic) { + for (CandidateInfo secondCandidate : secondCandidates) { + final PsiElement psiElement = secondCandidate.getElement(); + if (psiElement instanceof PsiMethod) { + final boolean oppositeStatic = ((PsiMethod)psiElement).hasModifierProperty(PsiModifier.STATIC); + if (shouldBeStatic && !oppositeStatic || !shouldBeStatic && oppositeStatic) { + return null; + } + } + } + return candidateInfo; } } } + return null; } private boolean isCorrectAssignment(PsiType[] signatureParameterTypes2, diff --git a/java/java-tests/testData/codeInsight/completion/normal/MulticaretTyping.java b/java/java-tests/testData/codeInsight/completion/normal/MulticaretTyping.java new file mode 100644 index 000000000000..00d3186f4ef2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/MulticaretTyping.java @@ -0,0 +1,4 @@ +class Foo {{ + System.out.p<caret> + System.out.p<caret> +}} diff --git a/java/java-tests/testData/codeInsight/completion/normal/MulticaretTyping_after.java b/java/java-tests/testData/codeInsight/completion/normal/MulticaretTyping_after.java new file mode 100644 index 000000000000..87debd854955 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/MulticaretTyping_after.java @@ -0,0 +1,4 @@ +class Foo {{ + System.out.append(<caret>) + System.out.append(<caret>) +}} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures7.java index 506accd112c3..d0d4dbc5324a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures7.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures7.java @@ -27,7 +27,7 @@ class UnsupportedFeatures { for (String s : args) { System.out.println(s); } List<String> list = - new ArrayList<>(); + new ArrayList<error descr="Diamond types are not supported at this language level"><></error>(); for (String s : list) {} Arrays.asList(""); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java index f51647ab0a23..fbbe91649ddb 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java @@ -97,14 +97,14 @@ interface I<T> { class FI1 { I<? extends String> i1 = new I<<error descr="Cannot use ''<>'' with anonymous inner classes"></error>>() { @Override - public <error descr="'m()' in 'Anonymous class derived from I' clashes with 'm()' in 'I'; attempting to use incompatible return type">String</error> m() { + public String m() { return null; } }; I<?> i2 = new I<<error descr="Cannot use ''<>'' with anonymous inner classes"></error>>() { @Override - public <error descr="'m()' in 'Anonymous class derived from I' clashes with 'm()' in 'I'; attempting to use incompatible return type">Object</error> m() { + public Object m() { return null; } }; @@ -157,14 +157,14 @@ class ParenthTest<T extends TZ> { class TestWildcardInference { interface A<T> { } - + class B<V> implements A<V> { B(C<V> v) { } } - + class C<E> {} - + class U { void foo() { C<? extends Number> x = null; @@ -202,13 +202,13 @@ class Another { System.out.println(i); - <error descr="Incompatible types. Found: 'Outer2.Inner2<java.lang.String>', required: 'Outer2.Inner2<java.lang.String>'">Outer2<Integer>.Inner2<String> i5 = new Outer2<>().new Inner2<>();</error> + <error descr="Incompatible types. Found: 'Outer2.Inner2<java.lang.String>', required: 'Outer2<java.lang.Integer>.Inner2<java.lang.String>'">Outer2<Integer>.Inner2<String> i5 = new Outer2<>().new Inner2<>();</error> } static Outer m() {return null;} static <T extends Outer> T m1() {return null;} static <T> T m2() {return null;} - + } class TypeParamsExtendsList { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/typeAnnotations.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/typeAnnotations.java index 400a678da1ed..28035c8c1698 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/typeAnnotations.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/typeAnnotations.java @@ -111,6 +111,7 @@ class Outer { int @TA [] a @TA [] <error descr="Annotations are not allowed here">@TA</error> = (p != null ? p : mixedArrays); return a; } + void <error descr="Annotations are not allowed here">@TA</error> misplaced() { } @TA Outer() { } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57413.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57413.java index 7236a9bcec95..de27a241d858 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57413.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57413.java @@ -2,6 +2,6 @@ class A<T> { <T extends A<T>> void foo(T x){} void bar(A<?> x){ - <error descr="Inferred type 'A<capture<?>>' for type parameter 'T' is not within its bound; should extend 'A<A<capture<?>>>'">foo(x)</error>; + <error descr="Inferred type 'capture<?>' for type parameter 'T' is not within its bound; should extend 'A<capture<? extends A<capture<?>>>>'">foo(x)</error>; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java index 7556292ef538..298a33dcbdf6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java @@ -142,7 +142,7 @@ class S1 { } void bar(List<? extends S1> k) { - f<error descr="'f(java.util.List<capture<? extends S1>>, capture<? extends S1>)' in 'S1' cannot be applied to '(java.util.List<capture<? extends S1>>, S1)'">(k, k.get(0))</error>; + f<error descr="'f(java.util.List<capture<? extends S1>>, capture<? extends S1>)' in 'S1' cannot be applied to '(java.util.List<capture<? extends S1>>, capture<? extends S1>)'">(k, k.get(0))</error>; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/LiftedCaptureToOuterCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/LiftedCaptureToOuterCall.java new file mode 100644 index 000000000000..75d3b8ab6123 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/LiftedCaptureToOuterCall.java @@ -0,0 +1,16 @@ +class Test { + + class Foo<K> {} + + void test(Foo<? extends String> p) { + foo(bar(p)) ; + } + + <T> T bar(Foo<T> p) { + return null; + } + + <K> K foo(K p) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/NestedCallsSameMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/NestedCallsSameMethod.java index eaafb1b96716..458171f5b51a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/NestedCallsSameMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/NestedCallsSameMethod.java @@ -1,3 +1,41 @@ +import java.util.List; + +import java.util.function.Function; + +abstract class Main2 { + void address(Foo sa) { + String ds = foobar(foobar(sa, Foo::getBar), Bar ::getName); + Function<Foo, Bar> f = null; + String ds1 = foobar(foobar(sa, f), null); + } + + abstract <T, V> V foobar(T t, Function<T, V> mapper); + + class Foo { + Bar getBar() { + return new Bar(); + } + } + + class Bar { + String getName(){ + return null; + } + } +} + + +class Main0 { + <T> List<T> foo(T t){ + return null; + } + + { + foo(foo("")); + } +} + + class Main { static <T> T foo(T t) { return null; } @@ -14,6 +52,6 @@ class Main1 { static <B> B bar(B t) { return null;} static { - long l = foo(bar(1)); + //long l = foo(bar(1)); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/SiteSubstitutionForReturnConstraint.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/SiteSubstitutionForReturnConstraint.java new file mode 100644 index 000000000000..ca5ad38ddfab --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/SiteSubstitutionForReturnConstraint.java @@ -0,0 +1,21 @@ +import java.util.function.Function; +import java.util.stream.Collector; + +class Collectors { + + public static <A,R,RR> void collectingAndThen(Function<R, RR> finisher, Function<A, R> finisher1) { + Function<A, RR> f = finisher1.andThen(finisher); + } + +} + + +class Collectors1 { + public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Function<R, RR> finisher, Function<A, R> function) { + return factory(function.andThen(finisher)); + } + + static <Ts, As, Rs> Collector<Ts, As, Rs> factory(Function<As, Rs> f) { + return null; + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeAmbiguity.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeAmbiguity.java index 8ee9852f366f..70a6e70c310c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeAmbiguity.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeAmbiguity.java @@ -40,6 +40,6 @@ class AAmbiguous { } public static void main(Promise<String> helloWorld) { - helloWorld.then<error descr="Ambiguous method call: both 'Promise.then(Function<? super String,Promise<Integer>>)' and 'Promise.then(AsyncFunction<? super String,Promise<Integer>>)' match">(AAmbiguous::calculateLength)</error>; + helloWorld.then<error descr="Ambiguous method call: both 'Promise.then(Function<? super String, Promise<Integer>>)' and 'Promise.then(AsyncFunction<? super String, Promise<Integer>>)' match">(AAmbiguous::calculateLength)</error>; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility1.java index 84e929697a92..d62afb3fdfcd 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility1.java @@ -21,9 +21,9 @@ class Test { } void foo(Foo<String> as, final Foo<Character> ac) { - boolean b1 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> false)</error>); - String s1 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> "")</error>); - boolean b2 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> "")</error>); + boolean b1 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character, Boolean>)' and 'Foo.forAll(II<Character, String>)' match">(c -> false)</error>); + String s1 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character, Boolean>)' and 'Foo.forAll(II<Character, String>)' match">(c -> "")</error>); + boolean b2 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character, Boolean>)' and 'Foo.forAll(II<Character, String>)' match">(c -> "")</error>); String s2 = as.forAll2(s -> ac.forAll2(<error descr="Incompatible return type boolean in lambda expression">c -> false</error>)); boolean b3 = as.forAll((I<String, Boolean>)s -> ac.forAll((I<Character, Boolean>)<error descr="Incompatible return type String in lambda expression">c -> ""</error>)); String s3 = as.forAll((II<String, String>)s -> ac.forAll((II<Character, String>)<error descr="Incompatible return type boolean in lambda expression">c -> false</error>)); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/DefaultMethodOverrideEquivalentObject.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/DefaultMethodOverrideEquivalentObject.java index cb671b7cd6c0..84b2259286fa 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/DefaultMethodOverrideEquivalentObject.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/DefaultMethodOverrideEquivalentObject.java @@ -2,4 +2,5 @@ interface A { default String <error descr="Default method 'toString' overrides a member of 'java.lang.Object'">toString</error>() { return ""; } + default void finalize() throws Throwable { } }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/AccessModifiers.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/AccessModifiers.java index 40811fd1f7a7..bc235b224c31 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/AccessModifiers.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/AccessModifiers.java @@ -29,7 +29,7 @@ class AlienTest { <error descr="Incompatible types. Found: '<method reference>', required: 'AlienTest.IInt'">IInt i2 = MyTest::foo;</error> <error descr="Incompatible types. Found: '<method reference>', required: 'AlienTest.IInt'">IInt i3 = MyTest::bar;</error> <error descr="Incompatible types. Found: '<method reference>', required: 'AlienTest.IIntInt'">IIntInt i4 = MyTest::bar;</error> - <error descr="Incompatible types. Found: '<method reference>', required: 'AlienTest.IInt'">IInt i5 = MyTest::baz;</error> + IInt i5 = <error descr="Non-static method cannot be referenced from a static context">MyTest::baz</error>; IInt i6 = <error descr="'foo(int)' is not public in 'MyTest.Foo'. Cannot be accessed from outside package">MyTest.foo::foo</error>; IInt i7 = MyTest.<error descr="'MyTest.Foo' has private access in 'MyTest'">Foo</error>::foo; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/ReturnTypeSpecific.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/ReturnTypeSpecific.java index 848c423302c6..0696aadf6179 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/ReturnTypeSpecific.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/ReturnTypeSpecific.java @@ -29,7 +29,7 @@ class MyTest { } public static void main(String[] args) { - foo<error descr="Ambiguous method call: both 'MyTest.foo(I1)' and 'MyTest.foo(I2)' match">(Foo::m)</error>; + foo<error descr="Ambiguous method call: both 'MyTest.foo(I2)' and 'MyTest.foo(I3)' match">(Foo::m)</error>; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/StaticProblems.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/StaticProblems.java index 3375ceb2a090..8d482f2920ab 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/StaticProblems.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/StaticProblems.java @@ -41,14 +41,14 @@ class MyTest1 { static void call2(I2 s) { } static void test1() { - <error descr="Incompatible types. Found: '<method reference>', required: 'MyTest1.I1'">I1 s1 = MyTest1 ::m1;</error> - call1<error descr="'call1(MyTest1.I1)' in 'MyTest1' cannot be applied to '(<method reference>)'">(MyTest1::m1)</error>; + I1 s1 = <error descr="Non-static method cannot be referenced from a static context">MyTest1 ::m1</error>; + call1(<error descr="Non-static method cannot be referenced from a static context">MyTest1::m1</error>); I1 s2 = MyTest1 :: m2; call1(MyTest1::m2); I1 s3 = MyTest1::m3; call1(MyTest1::m3); - <error descr="Incompatible types. Found: '<method reference>', required: 'MyTest1.I1'">I1 s4 = MyTest1::m4;</error> - call1<error descr="'call1(MyTest1.I1)' in 'MyTest1' cannot be applied to '(<method reference>)'">(MyTest1::m4)</error>; + I1 s4 = <error descr="Non-static method cannot be referenced from a static context">MyTest1::m4</error>; + call1(<error descr="Non-static method cannot be referenced from a static context">MyTest1::m4</error>); } static void test2() { @@ -90,14 +90,14 @@ class MyTest2 { static void call2(I2 s) { } static void test1() { - <error descr="Incompatible types. Found: '<method reference>', required: 'MyTest2.I1'">I1 s1 = MyTest2 ::m1;</error> - call1<error descr="'call1(MyTest2.I1)' in 'MyTest2' cannot be applied to '(<method reference>)'">(MyTest2::m1)</error>; + I1 s1 = <error descr="Non-static method cannot be referenced from a static context">MyTest2 ::m1</error>; + call1(<error descr="Non-static method cannot be referenced from a static context">MyTest2::m1</error>); I1 s2 = MyTest2 :: m2; call1(MyTest2::m2); I1 s3 = MyTest2::m3; call1(MyTest2::m3); - <error descr="Incompatible types. Found: '<method reference>', required: 'MyTest2.I1'">I1 s4 = MyTest2::m4;</error> - call1<error descr="'call1(MyTest2.I1)' in 'MyTest2' cannot be applied to '(<method reference>)'">(MyTest2::m4)</error>; + I1 s4 = <error descr="Non-static method cannot be referenced from a static context">MyTest2::m4</error>; + call1(<error descr="Non-static method cannot be referenced from a static context">MyTest2::m4</error>); } static void test2() { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/Varargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/Varargs.java index 66f4e0701b4b..e521df2c2d40 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/Varargs.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/Varargs.java @@ -55,7 +55,7 @@ class MyTest { { - <error descr="Incompatible types. Found: '<method reference>', required: 'MyTest.I1'">I1 i_1 = MyTest::_1;</error> + I1 i_1 = <error descr="Non-static method cannot be referenced from a static context">MyTest::_1</error>; <error descr="Incompatible types. Found: '<method reference>', required: 'MyTest.I1'">I1 i_2 = MyTest::_2;</error> <error descr="Incompatible types. Found: '<method reference>', required: 'MyTest.I1'">I1 i_3 = MyTest::_3;</error> <error descr="Incompatible types. Found: '<method reference>', required: 'MyTest.I1'">I1 i_4 = MyTest::_4;</error> diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/VarargsInReceiverPosition.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/VarargsInReceiverPosition.java index f6c1e3f67c0e..cf2151dc76d8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/VarargsInReceiverPosition.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/VarargsInReceiverPosition.java @@ -3,7 +3,7 @@ import java.util.*; class Test { void test() { Comparator<Test> r2 = Test::yyy; - <error descr="Incompatible types. Found: '<method reference>', required: 'Comparator1<Test>'">Comparator1<Test> c1 = Test::yyy;</error> + Comparator1<Test> c1 = <error descr="Non-static method cannot be referenced from a static context">Test::yyy</error>; <error descr="Incompatible types. Found: '<method reference>', required: 'Comparator1<Test>'">Comparator1<Test> c2 = Test::xxx;</error> } int yyy(Test... p) { return 1; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/DiamondInLambdaReturn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/DiamondInLambdaReturn.java new file mode 100644 index 000000000000..8f547d2038ba --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/DiamondInLambdaReturn.java @@ -0,0 +1,9 @@ +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class Test { + Set<String> collect(Stream<String> map){ + return map.collect(Collectors.toCollection(() -> new LinkedHashSet<>())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA118965.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA118965.java new file mode 100644 index 000000000000..207a091eb3c6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA118965.java @@ -0,0 +1,37 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Stream; + +import static java.util.Arrays.asList; + +class Test { + + public static void main(String[] args) { + + List<String> list = new ArrayList<>(); // JDK 7 diamond operator + list.add("aaa"); + list.add("bb"); + list.add("cccc"); + list.add("dd"); + list.add("e"); + + schwartz(list.stream(), s -> s.length()) + .forEach(x -> { System.out.println(x); }); + } + + public static<T, R extends Comparable<? super R>> Stream<T> schwartz(Stream<T> stream, Function<T, R> f) { + + // class Pair - type of second element of pair must be Comparable + final class Pair<F, S extends Comparable<? super S>> { + public final F first; + public final S second; + public Pair(F first, S second){ this.first = first; this.second = second; } + } + + return stream + .map(t -> new Pair<>(t, f.apply(t))) + .sorted((p1, p2) -> p1.second.compareTo(p2.second)) + .map(p -> p.first); + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java index ab7614c23c55..18f5026255c6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java @@ -53,7 +53,7 @@ class Test { Test s1 = staticCall(Test::n0); Test s2 = staticCall(Test::n1); Test s3 = staticCall<error descr="Cannot resolve method 'staticCall(<method reference>)'">(Test::n2)</error>; - Test s4 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test,String>)' match">(Test::n01)</error>; - Test s5 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test,String>)' match">(Test::n012)</error>; + Test s4 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test, String>)' match">(Test::n01)</error>; + Test s5 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test, String>)' match">(Test::n012)</error>; } }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/ReturnTypeCheckForRawReceiver.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/ReturnTypeCheckForRawReceiver.java new file mode 100644 index 000000000000..853b02ada009 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/ReturnTypeCheckForRawReceiver.java @@ -0,0 +1,15 @@ +class Test { + + static class Foo<X> { + X m() { return null;} + } + + interface I { + Foo<Object> _i(Foo<String> fs); + } + + static void foo(I i) { } + { + foo(<error descr="Bad return type in method reference: cannot convert java.lang.String to Test.Foo<java.lang.Object>">Foo::m</error>); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/StaticNonStaticReferenceTypeAmbiguity.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/StaticNonStaticReferenceTypeAmbiguity.java new file mode 100644 index 000000000000..7430c7c889e9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/StaticNonStaticReferenceTypeAmbiguity.java @@ -0,0 +1,15 @@ +class Test { + + interface I { + void m(Test rec, String s); + } + + void m(Test t, String s) {} + void m(String s) {} + + static void m(Test t, Object s) {} + + static void test() { + <error descr="Incompatible types. Found: '<method reference>', required: 'Test.I'">I i = Test::m;</error> + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/LambdaFormalParamTypesParametrization.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/LambdaFormalParamTypesParametrization.java new file mode 100644 index 000000000000..0dbcc3e35fec --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/LambdaFormalParamTypesParametrization.java @@ -0,0 +1,10 @@ +import java.util.function.Function; + +class Test { + + <U, V> void foo(Function<U, ? extends V> m) {} + + { + foo((String e) -> e.length()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java new file mode 100644 index 000000000000..fa9df550e936 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java @@ -0,0 +1,108 @@ +import java.util.List; + +class SimpleDependency { + + interface I<R extends U, U> { + R m(); + } + + { + I<? extends String, ? extends String> k = () -> null; + I<? extends String, String> k1 = () -> null; + I<? extends List<String>, List<String>> k2 = () -> null; + I<? extends List<String>, ? extends List<String>> k3 = () -> null; + I<? extends List<? extends String>, ? extends List<String>> k4 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<? extends List<? extends String>, List<? extends String>> k5 = () -> null; + I<? extends List<? extends String>, ? extends List<? extends String>> k6 = () -> null; + + I<? super String, String> s = () -> null; + I<? super List<String>, List<? extends String>> s1 = () -> null; + } +} + +class NoDependency { + interface I<T, U> { + T m(); + } + + { + I<? extends String, ? extends String> k = () -> null; + } +} + +class ExtendsList { + interface I<R extends List<T>, T> { + R m(); + } + + { + I<?, ? extends String> n = <error descr="Cannot infer functional interface type">() -> null</error>; + I<?, ?> n1 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<?, String> n2 = <error descr="Cannot infer functional interface type">() -> null</error>; + + + I<? extends List<?>, String> e1 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<? extends List<?>, ?> e2 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<? extends List<String>, ? extends String> e3 = () -> null; + I<? extends List<? extends String>, ? extends String> e4 = <error descr="Cannot infer functional interface type">() -> null</error>; + + I<? super List<String>, ? extends String> s1 = () -> null; + I<? super List<String>, String> s2 = () -> null; + } +} + +class MultipleBounds { + interface I<R extends List<T> & Comparable<T>, T> { + R m(); + } + + interface LC<K> extends List<K>, Comparable<K> {} + + { + I<?, String> n = <error descr="Cannot infer functional interface type">() -> null</error>; + + I<? extends List<String>, ? extends String> e1 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<? extends Comparable<String>, ? extends String> e2 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<? extends LC<String>, ? extends String> e3 = () -> null; + I<? extends LC<String>, String> e4 = () -> null; + I<? extends LC<? extends String>, String> e5 = <error descr="Cannot infer functional interface type">() -> null</error>; + } +} + +class FirstIndependentBound { + interface I<R extends List<String> & Comparable<T>, T> { + R m(); + } + + interface LC<K> extends List<String>, Comparable<K> {} + + { + I<?, String> n = <error descr="Cannot infer functional interface type">() -> null</error>; + + I<? extends List<String>, ? extends String> e1 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<? extends Comparable<String>, ? extends String> e2 = () -> null; + I<? extends LC<String>, ? extends String> e3 = () -> null; + I<? extends LC<String>, String> e4 = () -> null; + I<? extends LC<? extends String>, String> e5 = <error descr="Cannot infer functional interface type">() -> null</error>; + } +} + + +class SecondIndependentBound { + interface I<R extends List<T> & Comparable<String>, T> { + R m(); + } + + interface LC<K> extends List<String>, Comparable<K> {} + + { + I<?, String> n = <error descr="Cannot infer functional interface type">() -> null</error>; + + I<? extends List<String>, ? extends String> e1 = () -> null; + I<? extends Comparable<String>, ? extends String> e2 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<? extends LC<String>, ? extends String> e3 = () -> null; + I<? extends LC<String>, String> e4 = () -> null; + I<? extends LC<? extends String>, String> e5 = <error descr="Cannot infer functional interface type">() -> null</error>; + I<? extends LC<? extends String>, ? extends String> e6 = <error descr="Cannot infer functional interface type">() -> null</error>; + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/PrimitiveParameterTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/PrimitiveParameterTypes.java new file mode 100644 index 000000000000..f339392c1bee --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/PrimitiveParameterTypes.java @@ -0,0 +1,13 @@ +class IDEA100385 { + void foo(N<Double> n){ + n.forEach((<error descr="Incompatible parameter types in lambda expression">double e</error>) -> { }); + } + static interface N<E> { + void forEach(Consumer<? extends E> consumer); + } + + interface Consumer<T> { + public void accept(T t); + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterEnumConstantWithoutClassInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterEnumConstantWithoutClassInitializer.java index 9ae8bed1d285..2369d9c9d05d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterEnumConstantWithoutClassInitializer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterEnumConstantWithoutClassInitializer.java @@ -1,9 +1,11 @@ // "Implement Methods" "true" enum E { - A { - public void foo() { - - } - }; - abstract void foo(); + A { + @Override + public int foo() { + return 0; + } + }; + + public abstract int foo(); }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterIDEA108454.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterIDEA108454.java new file mode 100644 index 000000000000..a7e8482f6d42 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterIDEA108454.java @@ -0,0 +1,17 @@ +// "Implement Methods" "true" +class Test { + class A<T> { + public class Inner { } + } + + interface B<T> { + T foo(); + } + + class D implements B<A<String>.Inner> { + @Override + public A<String>.Inner foo() { + return null; + } + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeEnumConstantWithoutClassInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeEnumConstantWithoutClassInitializer.java index 92bbb6aea212..518de23ab0c6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeEnumConstantWithoutClassInitializer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeEnumConstantWithoutClassInitializer.java @@ -1,5 +1,6 @@ // "Implement Methods" "true" enum E { - <caret>A; - public abstract void foo(); + <caret>A; + + public abstract int foo(); }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeIDEA108454.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeIDEA108454.java new file mode 100644 index 000000000000..32e8e5b5f4f4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeIDEA108454.java @@ -0,0 +1,12 @@ +// "Implement Methods" "true" +class Test { + class A<T> { + public class Inner { } + } + + interface B<T> { + T foo(); + } + + <caret>class D implements B<A<String>.Inner> { } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayList.java new file mode 100644 index 000000000000..aef9e753f716 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayList.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + List<String> names = persons.stream().map(Person::getName).collect(Collectors.toList()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListAndFilter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListAndFilter.java new file mode 100644 index 000000000000..4467078950cd --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListAndFilter.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + List<String> names = persons.stream().filter(person -> person != null).map(Person::getName).collect(Collectors.toList()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListLambda.java new file mode 100644 index 000000000000..e1517740be28 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectArrayListLambda.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + List<String> names = persons.stream().map(person -> "name: " + person.getName()).collect(Collectors.toList()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSet.java new file mode 100644 index 000000000000..022b8e3ae576 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSet.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + Set<String> names = persons.stream().map(Person::getName).collect(Collectors.toSet()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSetFieldInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSetFieldInitializer.java new file mode 100644 index 000000000000..edd903ab1769 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectHashSetFieldInitializer.java @@ -0,0 +1,16 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + Set<String> names = new HashSet<>(); + void collectNames(List<Person> persons){ + names.addAll(persons.stream().map(Person::getName).collect(Collectors.toList())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectLinkedHashSet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectLinkedHashSet.java new file mode 100644 index 000000000000..6bb6839b0cea --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectLinkedHashSet.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + Set<String> names = persons.stream().map(Person::getName).collect(Collectors.toCollection(() -> new LinkedHashSet<>())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSelfCollection.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSelfCollection.java new file mode 100644 index 000000000000..676c127d4a6f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSelfCollection.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public abstract class Collect implements Collection<String>{ + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + addAll(persons.stream().map(Person::getName).collect(Collectors.toList())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSetParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSetParameter.java new file mode 100644 index 000000000000..c8201c9b486e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectSetParameter.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" +import java.util.*; +import java.util.stream.Collectors; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons, Set<String> names){ + names.addAll(persons.stream().map(Person::getName).collect(Collectors.toList())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterNoBraces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterNoBraces.java new file mode 100644 index 000000000000..ab67b49343ca --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterNoBraces.java @@ -0,0 +1,10 @@ +// "Replace with forEach" "true" +import java.util.ArrayList; +import java.util.List; + +class Sample { + List<String> foo = new ArrayList<>(); + { + foo.stream().filter(s -> s != null).forEach(System.out::println); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterNormalNoBraces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterNormalNoBraces.java new file mode 100644 index 000000000000..b7c6bdeca41d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterNormalNoBraces.java @@ -0,0 +1,10 @@ +// "Replace with forEach" "true" +import java.util.ArrayList; +import java.util.List; + +class Sample { + List<String> foo = new ArrayList<>(); + { + foo.forEach(System.out::println); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayList.java new file mode 100644 index 000000000000..3114dd720dd3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayList.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" +import java.util.*; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + List<String> names = new ArrayList<>(); + for (Person person : pers<caret>ons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListAndFilter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListAndFilter.java new file mode 100644 index 000000000000..9a671cbafd0b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListAndFilter.java @@ -0,0 +1,19 @@ +// "Replace with collect" "true" +import java.util.*; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + List<String> names = new ArrayList<>(); + for (Person person : pers<caret>ons) { + if (person != null) { + names.add(person.getName()); + } + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListLambda.java new file mode 100644 index 000000000000..434c2c5a1bec --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectArrayListLambda.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" +import java.util.*; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + List<String> names = new ArrayList<>(); + for (Person person : pers<caret>ons) { + names.add("name: " + person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSet.java new file mode 100644 index 000000000000..9e1e0e52659d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSet.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" +import java.util.*; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + Set<String> names = new HashSet<>(); + for (Person person : pers<caret>ons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSetFieldInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSetFieldInitializer.java new file mode 100644 index 000000000000..44f39e19f3dc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectHashSetFieldInitializer.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" +import java.util.*; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + Set<String> names = new HashSet<>(); + void collectNames(List<Person> persons){ + for (Person person : pers<caret>ons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectLinkedHashSet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectLinkedHashSet.java new file mode 100644 index 000000000000..f3ffecc179d0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectLinkedHashSet.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" +import java.util.*; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + Set<String> names = new LinkedHashSet<>(); + for (Person person : pers<caret>ons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSelfCollection.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSelfCollection.java new file mode 100644 index 000000000000..1dbed313c132 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSelfCollection.java @@ -0,0 +1,16 @@ +// "Replace with collect" "true" +import java.util.*; + +public abstract class Collect implements Collection<String>{ + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons){ + for (Person person : pers<caret>ons) { + add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSetParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSetParameter.java new file mode 100644 index 000000000000..f7287c4b9a56 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectSetParameter.java @@ -0,0 +1,16 @@ +// "Replace with collect" "true" +import java.util.*; + +public class Collect { + class Person { + String getName() { + return ""; + } + } + + void collectNames(List<Person> persons, Set<String> names){ + for (Person person : pers<caret>ons) { + names.add(person.getName()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterNoBraces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterNoBraces.java new file mode 100644 index 000000000000..8c712761fb28 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterNoBraces.java @@ -0,0 +1,12 @@ +// "Replace with forEach" "true" +import java.util.ArrayList; +import java.util.List; + +class Sample { + List<String> foo = new ArrayList<>(); + { + for (String s : fo<caret>o) { + if (s != null) System.out.println(s); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeNormalNoBraces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeNormalNoBraces.java new file mode 100644 index 000000000000..0ad984469b06 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeNormalNoBraces.java @@ -0,0 +1,10 @@ +// "Replace with forEach" "true" +import java.util.ArrayList; +import java.util.List; + +class Sample { + List<String> foo = new ArrayList<>(); + { + for (String s : fo<caret>o) System.out.println(s); + } +} diff --git a/java/java-tests/testData/codeInsight/gotosuper/Lambda.after.java b/java/java-tests/testData/codeInsight/gotosuper/Lambda.after.java new file mode 100644 index 000000000000..2fe10c280c86 --- /dev/null +++ b/java/java-tests/testData/codeInsight/gotosuper/Lambda.after.java @@ -0,0 +1,9 @@ +interface I { + void <caret>run(); +} + +class Foo { + { + I i = () -> {}; + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/gotosuper/Lambda.java b/java/java-tests/testData/codeInsight/gotosuper/Lambda.java new file mode 100644 index 000000000000..26c024317a1d --- /dev/null +++ b/java/java-tests/testData/codeInsight/gotosuper/Lambda.java @@ -0,0 +1,9 @@ +interface I { + void run(); +} + +class Foo { + { + I i = ()<caret> -> {}; + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/gotosuper/LambdaMarker.java b/java/java-tests/testData/codeInsight/gotosuper/LambdaMarker.java new file mode 100644 index 000000000000..26c024317a1d --- /dev/null +++ b/java/java-tests/testData/codeInsight/gotosuper/LambdaMarker.java @@ -0,0 +1,9 @@ +interface I { + void run(); +} + +class Foo { + { + I i = ()<caret> -> {}; + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/fileEditorManager/src/Bar.java b/java/java-tests/testData/fileEditorManager/src/Bar.java new file mode 100644 index 000000000000..4843c680a616 --- /dev/null +++ b/java/java-tests/testData/fileEditorManager/src/Bar.java @@ -0,0 +1,5 @@ +public class Bar { + public String doIt() { + return ""; + } +} diff --git a/java/java-tests/testData/psi/shortenClassRefs/TypeAnnotatedRef.java b/java/java-tests/testData/psi/shortenClassRefs/TypeAnnotatedRef.java index b06887668d65..ded427d4aef0 100644 --- a/java/java-tests/testData/psi/shortenClassRefs/TypeAnnotatedRef.java +++ b/java/java-tests/testData/psi/shortenClassRefs/TypeAnnotatedRef.java @@ -1,15 +1,12 @@ -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; - -@Target({TYPE_USE}) @interface TA { } +import pkg.TA; class Outer { class Middle { class Inner { void m1(Outer.Middle.Inner p) { } - void m2(@TA Outer.Middle.Inner p) { } - void m3(Outer.@TA Middle.Inner p) { } - void m4(Outer.Middle.@TA @TA Inner p) { } + void m2(@pkg.TA Outer.Middle.Inner p) { } + void m3(Outer.@pkg.TA Middle.Inner p) { } + void m4(Outer.Middle.@pkg.TA @pkg.TA Inner p) { } } } } diff --git a/java/java-tests/testData/psi/shortenClassRefs/TypeAnnotatedRef_after.java b/java/java-tests/testData/psi/shortenClassRefs/TypeAnnotatedRef_after.java index 1c4c8d4a3ec5..fab10a32c52f 100644 --- a/java/java-tests/testData/psi/shortenClassRefs/TypeAnnotatedRef_after.java +++ b/java/java-tests/testData/psi/shortenClassRefs/TypeAnnotatedRef_after.java @@ -1,7 +1,4 @@ -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; - -@Target({TYPE_USE}) @interface TA { } +import pkg.TA; class Outer { class Middle { diff --git a/java/java-tests/testData/psi/shortenClassRefs/pkg/TA.java b/java/java-tests/testData/psi/shortenClassRefs/pkg/TA.java new file mode 100644 index 000000000000..abe2aca8d7ac --- /dev/null +++ b/java/java-tests/testData/psi/shortenClassRefs/pkg/TA.java @@ -0,0 +1,6 @@ +package pkg; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE_USE}) +@interface TA { } diff --git a/java/java-tests/testData/refactoring/introduceVariable/genericWithTwoParameters/after/Client.java b/java/java-tests/testData/refactoring/introduceVariable/genericWithTwoParameters/after/Client.java index 38d94b3a880b..c98b7fa857fc 100644 --- a/java/java-tests/testData/refactoring/introduceVariable/genericWithTwoParameters/after/Client.java +++ b/java/java-tests/testData/refactoring/introduceVariable/genericWithTwoParameters/after/Client.java @@ -2,6 +2,6 @@ import util.Pair; class Client { void method() { - Pair<String, Pair<Integer,Boolean>> p = PairProvider.getPair(); + Pair<String, Pair<Integer, Boolean>> p = PairProvider.getPair(); } }
\ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/AddAnnotationFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/AddAnnotationFixTest.java index 231a0cd45c0a..ec8b8dd49284 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/AddAnnotationFixTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/AddAnnotationFixTest.java @@ -27,7 +27,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.module.Module; @@ -51,6 +50,7 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.*; +import com.intellij.util.ObjectUtils; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -122,13 +122,7 @@ public class AddAnnotationFixTest extends UsefulTestCase { @NotNull private PsiModifierListOwner getOwner() { - CaretModel caretModel = myFixture.getEditor().getCaretModel(); - int position = caretModel.getOffset(); - PsiElement element = myFixture.getFile().findElementAt(position); - assert element != null; - PsiModifierListOwner container = AddAnnotationPsiFix.getContainer(element); - assert container != null; - return container; + return ObjectUtils.assertNotNull(AddAnnotationPsiFix.getContainer(myFixture.getFile(), myFixture.getCaretOffset())); } private void startListening(@NotNull final List<Trinity<PsiModifierListOwner, String, Boolean>> expectedSequence) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ImplementMethodsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ImplementMethodsTest.java index b5ab59a09c2a..6fd655344758 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/ImplementMethodsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/ImplementMethodsTest.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. @@ -15,13 +15,12 @@ */ package com.intellij.codeInsight; -import com.intellij.codeInsight.daemon.quickFix.LightQuickFixAvailabilityTestCase; +import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase; /** - * User: anna - * Date: 10/7/11 + * @author anna */ -public class ImplementMethodsTest extends LightQuickFixAvailabilityTestCase { +public class ImplementMethodsTest extends LightQuickFixParameterizedTestCase { public void test() throws Exception { doAllTests(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 4e8961dbe192..0b12b544bbfd 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -52,6 +52,7 @@ import com.intellij.psi.PsiFile import com.intellij.psi.PsiJavaFile import com.intellij.psi.statistics.StatisticsManager import com.intellij.psi.statistics.impl.StatisticsManagerImpl +import com.intellij.testFramework.EditorTestUtil import com.intellij.util.containers.ContainerUtil import org.jetbrains.annotations.NotNull @@ -1141,6 +1142,56 @@ class Foo {{ }}''' } + public void testMulticaret() { + doTestMulticaret """ +class Foo {{ + <selection>t<caret></selection>x; + <selection>t<caret></selection>x; +}}""", '\n', ''' +class Foo {{ + toString()<caret>x; + toString()<caret>x; +}}''' + } + + public void testMulticaretTab() { + doTestMulticaret """ +class Foo {{ + <selection>t<caret></selection>x; + <selection>t<caret></selection>x; +}}""", '\t', ''' +class Foo {{ + toString()<caret>; + toString()<caret>; +}}''' + } + + public void testMulticaretBackspace() { + doTestMulticaret """ +class Foo {{ + <selection>t<caret></selection>; + <selection>t<caret></selection>; +}}""", '\b\t', ''' +class Foo {{ + toString()<caret>; + toString()<caret>; +}}''' + } + + private doTestMulticaret(final String textBefore, final String toType, final String textAfter) { + EditorTestUtil.enableMultipleCarets() + try { + myFixture.configureByText "a.java", textBefore + type 'toStr' + assert lookup + type toType + myFixture.checkResult textAfter + } + finally { + EditorTestUtil.disableMultipleCarets() + } + } + private doTestBlockSelection(final String textBefore, final String toType, final String textAfter) { myFixture.configureByText "a.java", textBefore edt { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index f07a9635da0c..35b71f8cc33b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1403,6 +1403,33 @@ class Foo {{ } } + public void testPrimitiveSquareBracketWhenMultipleCaretsAreEnabled() { + EditorTestUtil.enableMultipleCarets() + try { + configureByFile("PrimitiveSquareBracket.java"); + type('['); + checkResultByFile("PrimitiveSquareBracket_after.java"); + } + finally { + EditorTestUtil.disableMultipleCarets() + } + } + + public void testMulticaretTyping() { + EditorTestUtil.enableMultipleCarets() + try { + configure() + assert lookup + type('p') + assert lookup + type('\n') + checkResult() + } + finally { + EditorTestUtil.disableMultipleCarets() + } + } + public void "test complete lowercase class name"() { myFixture.addClass("package foo; public class myClass {}") myFixture.configureByText "a.java", """ diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java index 1868d2196d7c..964566fcf5ff 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java @@ -39,6 +39,8 @@ public class AnnotationsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testInapplicable() { doTest(false); } public void testDuplicateAttribute() { doTest(false); } public void testDuplicateTarget() { doTest(false); } + public void testPingPongAnnotationTypesDependencies() { doTest(false);} + public void testClashMethods() { doTest(false);} public void testInvalidPackageAnnotationTarget() { doTest(BASE_PATH + "/" + getTestName(true) + "/package-info.java", false, false); } public void testPackageAnnotationNotInPackageInfo() { doTest(BASE_PATH + "/" + getTestName(true) + "/notPackageInfo.java", false, false); } @@ -46,9 +48,6 @@ public class AnnotationsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testTypeAnnotations() { doTest8(false); } public void testRepeatable() { doTest8(false); } - public void testPingPongAnnotationTypesDependencies() { doTest(false);} - public void testClashMethods() { doTest(false);} - private void doTest(boolean checkWarnings) { setLanguageLevel(LanguageLevel.JDK_1_7); doTest(BASE_PATH + "/" + getTestName(true) + ".java", checkWarnings, false); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java index b50052b71750..80448f9d3a96 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java @@ -368,7 +368,7 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase { public void testAutoImportOfGenericReference() throws Throwable { - @NonNls final String text = "class S {{ new ArrayList<caret><> }}"; + @NonNls final String text = "class S {{ new ArrayList<caret><String> }}"; configureByText(StdFileTypes.JAVA, text); boolean old = CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY; CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = true; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java new file mode 100644 index 000000000000..599ae74cd00d --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java @@ -0,0 +1,48 @@ +/* + * 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. + * 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.codeInsight.daemon.lambda; + +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NonNls; + +public class FunctionalTypeWildcardParameterizationTest extends LightDaemonAnalyzerTestCase { + @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization"; + + public void testNonWildcardParametrization() throws Exception { + doTest(); + } + + public void testLambdaFormalParamTypesParametrization() throws Exception { + doTest(); + } + + public void testPrimitiveParameterTypes() throws Exception { + doTest(); + } + + private void doTest() { + IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable()); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false); + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 1119a0d6d4df..8af0821571d6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -28,7 +28,7 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } - public void _testNestedCallsSameMethod() throws Exception { + public void testNestedCallsSameMethod() throws Exception { doTest(); } @@ -160,6 +160,14 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testLiftedCaptureToOuterCall() throws Exception { + doTest(); + } + + public void testSiteSubstitutionForReturnConstraint() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index 89ddef20df0e..826193c90f90 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -138,6 +138,14 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testDiamondInLambdaReturn() throws Exception { + doTest(); + } + + public void testIDEA118965() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java index e944269c098b..83f0dfac5c1e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java @@ -173,6 +173,14 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testReturnTypeCheckForRawReceiver() throws Exception { + doTest(); + } + + public void testStaticNonStaticReferenceTypeAmbiguity() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/navigation/JavaGotoSuperTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/navigation/JavaGotoSuperTest.java new file mode 100644 index 000000000000..313720456ae5 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/navigation/JavaGotoSuperTest.java @@ -0,0 +1,52 @@ +package com.intellij.codeInsight.navigation; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInsight.CodeInsightActionHandler; +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.codeInsight.daemon.LineMarkerInfo; +import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl; +import com.intellij.lang.CodeInsightActions; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.editor.Document; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class JavaGotoSuperTest extends LightDaemonAnalyzerTestCase { + @NotNull + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath(); + } + + protected String getBasePath() { + return "/codeInsight/gotosuper/"; + } + + public void testLambda() throws Throwable { + doTest(); + } + + public void testLambdaMarker() throws Exception { + configureByFile(getBasePath() + getTestName(false) + ".java"); + int offset = myEditor.getCaretModel().getOffset(); + + doHighlighting(); + Document document = getEditor().getDocument(); + List<LineMarkerInfo> markers = DaemonCodeAnalyzerImpl.getLineMarkers(document, getProject()); + for (LineMarkerInfo info : markers) { + if (info.endOffset >= offset && info.startOffset <= offset) { + assertEquals("<html><body>Overrides method in 'I'</body></html>", info.getLineMarkerTooltip()); + return; + } + } + fail("Gutter expected"); + } + + private void doTest() throws Throwable { + configureByFile(getBasePath() + getTestName(false) + ".java"); + final CodeInsightActionHandler handler = CodeInsightActions.GOTO_SUPER.forLanguage(JavaLanguage.INSTANCE); + handler.invoke(getProject(), getEditor(), getFile()); + checkResultByFile(getBasePath() + getTestName(false) + ".after.java"); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy index f186f9e8f5c8..6373bc3ce307 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy @@ -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. @@ -15,15 +15,22 @@ */ package com.intellij.codeInsight.psi -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile +import com.intellij.pom.java.LanguageLevel +import com.intellij.psi.* +import com.intellij.psi.impl.source.PsiImmediateClassType import com.intellij.testFramework.LightIdeaTestCase -@SuppressWarnings(["GrUnresolvedAccess", "GroovyAssignabilityCheck"]) +@SuppressWarnings("GroovyAssignabilityCheck") class AnnotatedTypeTest extends LightIdeaTestCase { + private PsiFile context + private PsiElementFactory factory + + public void setUp() throws Exception { + super.setUp() + factory = javaFacade.elementFactory + context = createFile("typeCompositionTest.java", """ +package pkg; - public void testTypeComposition() { - PsiFile context = createFile("typeCompositionTest.java", """ import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; @@ -33,31 +40,55 @@ import static java.lang.annotation.ElementType.*; class E1 extends Exception { } class E2 extends Exception { } """) - PsiElement psi + } + + public void testPrimitiveArrayType() { + doTest("@A @TA(1) int @TA(2) [] a", "@pkg.TA(1) int @pkg.TA(2) []", "int[]") + } - psi = javaFacade.elementFactory.createStatementFromText("@A @TA(1) int @TA(2) [] a", context) - assertEquals("@TA(1) int @TA(2) []", psi.declaredElements[0].type.presentableText) + public void testEllipsisType() { + def psi = factory.createParameterFromText("@TA int @TA ... p", context) + assertTypeText(psi.type, "@pkg.TA int @pkg.TA ...", "int...") + } - psi = javaFacade.elementFactory.createStatementFromText("try { } catch (@A @TA(1) E1 | @TA(2) E2 e) { }", context) - assertEquals("@TA(1) E1 | @TA(2) E2", psi.catchBlockParameters[0].type.presentableText) + public void testClassReferenceType() { + doTest("@A @TA(1) String s", "java.lang.@pkg.TA(1) String", "java.lang.String") + doTest("@A java.lang.@TA(1) String s", "java.lang.@pkg.TA(1) String", "java.lang.String") + } - psi = javaFacade.elementFactory.createStatementFromText("@A @TA(1) String @TA(2) [] f @TA(3) []", context) - assertEquals("@TA(1) String @TA(2) [] @TA(3) []", psi.declaredElements[0].type.presentableText) + public void testCStyleArrayType() { + doTest("@A @TA(1) String @TA(2) [] f @TA(3) []", "java.lang.@pkg.TA(1) String @pkg.TA(2) [] @pkg.TA(3) []", "java.lang.String[][]") + } - psi = javaFacade.elementFactory.createStatementFromText("Class<@TA(1) ?> c", context) - assertEquals("Class<@TA(1) ?>", psi.declaredElements[0].type.presentableText) + public void testWildcardType() { + doTest("Class<@TA(1) ?> c", "java.lang.Class<@pkg.TA(1) ?>", "java.lang.Class<?>") + } - psi = javaFacade.elementFactory.createStatementFromText("Class<@TA String> cs = new Class<>()", context) - assertEquals("Class<@TA String>", psi.declaredElements[0].initializer.type.presentableText) + public void testDisjunctionType() { + def psi = factory.createStatementFromText("try { } catch (@A @TA(1) E1 | @TA(2) E2 e) { }", context) + assertTypeText(psi.catchBlockParameters[0].type, "pkg.@pkg.TA(1) E1 | pkg.@pkg.TA(2) E2", "pkg.E1 | pkg.E2") + } - psi = javaFacade.elementFactory.createStatementFromText("@A @TA(1) String s", context) - assertEquals("@TA(1) String", psi.declaredElements[0].type.presentableText) + public void testDiamondType() { + def psi = factory.createStatementFromText("Class<@TA String> cs = new Class<>()", context) + assertTypeText(psi.declaredElements[0].initializer.type, "java.lang.Class<java.lang.@pkg.TA String>", "java.lang.Class<java.lang.String>") + } - psi = javaFacade.elementFactory.createStatementFromText("@A java.lang.@TA(1) String s", context) - assertEquals("@TA(1) String", psi.declaredElements[0].type.presentableText) + public void testImmediateClassType() { + def aClass = javaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT) + def statement = factory.createStatementFromText("@TA int x", context) + def annotations = statement.declaredElements[0].modifierList.annotations + def type = new PsiImmediateClassType(aClass, PsiSubstitutor.EMPTY, LanguageLevel.JDK_1_8, annotations) + assertTypeText(type, "java.lang.@pkg.TA Object", CommonClassNames.JAVA_LANG_OBJECT) + } - psi = javaFacade.elementFactory.createStatementFromText("Collection<? extends> s", context) - assertEquals("Collection<?>", psi.declaredElements[0].type.presentableText) + private void doTest(String text, String annotated, String canonical) { + def psi = factory.createStatementFromText(text, context) + assertTypeText(psi.declaredElements[0].type, annotated, canonical) } + private static void assertTypeText(PsiType type, String annotated, String canonical) { + assert type.getCanonicalText(true) == annotated + assert type.getCanonicalText(false) == canonical + } } diff --git a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java index c2cef13e6ea8..bfd1de796f90 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java @@ -194,7 +194,7 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { PsiDirectory psiDirectory = FindInProjectUtil.getPsiDirectory(findModel, myProject); List<UsageInfo> result = new ArrayList<UsageInfo>(); final CommonProcessors.CollectProcessor<UsageInfo> collector = new CommonProcessors.CollectProcessor<UsageInfo>(result); - FindInProjectUtil.findUsages(findModel, psiDirectory, myProject, true, collector, new FindUsagesProcessPresentation(FindInProjectUtil.setupViewPresentation(true, findModel))); + FindInProjectUtil.findUsages(findModel, psiDirectory, myProject, collector, new FindUsagesProcessPresentation(FindInProjectUtil.setupViewPresentation(true, findModel))); return result; } diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.java index fba5b6e5265d..7770c5e4a1f9 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.java @@ -34,6 +34,7 @@ import com.intellij.testFramework.SkipSlowTestLocally; import com.intellij.util.indexing.MapIndexStorage; import com.intellij.util.indexing.StorageException; import com.intellij.util.io.*; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -113,7 +114,7 @@ public class IndexTest extends IdeaTestCase { private PersistentHashMap<Integer, Collection<String>> createMetaIndex(File metaIndexFile) throws IOException { return new PersistentHashMap<Integer, Collection<String>>(metaIndexFile, new EnumeratorIntegerDescriptor(), new DataExternalizer<Collection<String>>() { @Override - public void save(DataOutput out, Collection<String> value) throws IOException { + public void save(@NotNull DataOutput out, Collection<String> value) throws IOException { DataInputOutputUtil.writeINT(out, value.size()); for (String key : value) { out.writeUTF(key); @@ -121,7 +122,7 @@ public class IndexTest extends IdeaTestCase { } @Override - public Collection<String> read(DataInput in) throws IOException { + public Collection<String> read(@NotNull DataInput in) throws IOException { final int size = DataInputOutputUtil.readINT(in); final List<String> list = new ArrayList<String>(); for (int idx = 0; idx < size; idx++) { diff --git a/java/java-tests/testSrc/com/intellij/index/StringIndex.java b/java/java-tests/testSrc/com/intellij/index/StringIndex.java index a12f58fbf137..7d2dd108ceac 100644 --- a/java/java-tests/testSrc/com/intellij/index/StringIndex.java +++ b/java/java-tests/testSrc/com/intellij/index/StringIndex.java @@ -1,3 +1,18 @@ +/* + * 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. + * 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.index; import com.intellij.openapi.util.Factory; @@ -28,7 +43,7 @@ public class StringIndex { myIndex.setInputIdToDataKeysIndex(factory); } - public List<String> getFilesByWord(String word) throws StorageException { + public List<String> getFilesByWord(@NotNull String word) throws StorageException { return myIndex.getData(word).toValueList(); } diff --git a/java/java-tests/testSrc/com/intellij/openapi/editor/impl/JavaFileEditorManagerTest.java b/java/java-tests/testSrc/com/intellij/openapi/editor/impl/JavaFileEditorManagerTest.java new file mode 100644 index 000000000000..2a985b873ee3 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/openapi/editor/impl/JavaFileEditorManagerTest.java @@ -0,0 +1,54 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.impl; + +import com.intellij.openapi.fileEditor.FileEditorManagerTestCase; +import com.intellij.testFramework.PlatformTestUtil; +import org.jdom.JDOMException; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +/** + * @author Dmitry Avdeev + */ +public class JavaFileEditorManagerTest extends FileEditorManagerTestCase { + + public void testAsyncOpening() throws JDOMException, ExecutionException, InterruptedException, IOException { + openFiles("<component name=\"FileEditorManager\">\n" + + " <leaf>\n" + + " <file leaf-file-name=\"Bar.java\" pinned=\"false\" current=\"true\" current-in-tab=\"true\">\n" + + " <entry file=\"file://$PROJECT_DIR$/src/Bar.java\">\n" + + " <provider selected=\"true\" editor-type-id=\"text-editor\">\n" + + " <state vertical-scroll-proportion=\"0.032882012\" vertical-offset=\"0\" max-vertical-offset=\"517\">\n" + + " <caret line=\"1\" column=\"26\" selection-start=\"45\" selection-end=\"45\" />\n" + + " <folding>\n" + + " <element signature=\"e#69#70#0\" expanded=\"true\" />\n" + + " </folding>\n" + + " </state>\n" + + " </provider>\n" + + " </entry>\n" + + " </file>\n" + + " </leaf>\n" + + " </component>"); + } + + @Override + protected String getTestDataPath() { + return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + "/java/java-tests/testData/fileEditorManager"; + } +} diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/AbstractJavaFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/AbstractJavaFormatterTest.java index 58c02ef225b3..ab057c436baa 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/AbstractJavaFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/AbstractJavaFormatterTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -42,6 +42,7 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.util.EnumMap; +import java.util.List; import java.util.Map; /** @@ -51,13 +52,20 @@ import java.util.Map; * @since Apr 27, 2010 6:26:29 PM */ public abstract class AbstractJavaFormatterTest extends LightIdeaTestCase { - @NotNull - public static String shiftIndentInside(@NotNull String initial, final int i, boolean shiftEmptyLines) throws IOException { + public static String shiftIndentInside(@NotNull String initial, final int i, boolean shiftEmptyLines) { StringBuilder result = new StringBuilder(initial.length()); - LineReader reader = new LineReader(new ByteArrayInputStream(initial.getBytes())); + List<byte[]> lines; + try { + LineReader reader = new LineReader(new ByteArrayInputStream(initial.getBytes("UTF-8"))); + lines = reader.readLines(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + boolean first = true; - for (byte[] line : reader.readLines()) { + for (byte[] line : lines) { try { if (!first) result.append('\n'); if (line.length > 0 || shiftEmptyLines) { @@ -75,7 +83,6 @@ public abstract class AbstractJavaFormatterTest extends LightIdeaTestCase { protected enum Action {REFORMAT, INDENT} - public static JavaCodeStyleSettings getJavaSettings() { return getSettings().getRootSettings().getCustomSettings(JavaCodeStyleSettings.class); } @@ -116,20 +123,15 @@ public abstract class AbstractJavaFormatterTest extends LightIdeaTestCase { return rootSettings.getCommonSettings(JavaLanguage.INSTANCE); } - //public static JavaCodeStyleSettings getJavaSettings() { - // CodeStyleSettings rootSettings = CodeStyleSettingsManager.getSettings(getProject()); - // return rootSettings.getCustomSettings(JavaCodeStyleSettings.class); - //} - // public static CommonCodeStyleSettings.IndentOptions getIndentOptions() { return getSettings().getRootSettings().getIndentOptions(StdFileTypes.JAVA); } - public void doTest() throws Exception { + public void doTest() { doTest(getTestName(false) + ".java", getTestName(false) + "_after.java"); } - public void doTest(@NonNls String fileNameBefore, @NonNls String fileNameAfter) throws Exception { + public void doTest(@NonNls String fileNameBefore, @NonNls String fileNameAfter) { doTextTest(Action.REFORMAT, loadFile(fileNameBefore), loadFile(fileNameAfter)); } @@ -137,7 +139,7 @@ public abstract class AbstractJavaFormatterTest extends LightIdeaTestCase { doTextTest(Action.REFORMAT, text, textAfter); } - public void doTextTest(@NotNull final Action action, @NotNull final String text, @NotNull String textAfter) throws IncorrectOperationException { + public void doTextTest(@NotNull final Action action, @NotNull String text, @NotNull String textAfter) throws IncorrectOperationException { final PsiFile file = createFile("A.java", text); final PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject()); final Document document = manager.getDocument(file); @@ -204,7 +206,7 @@ public abstract class AbstractJavaFormatterTest extends LightIdeaTestCase { return document.getText(); } - public void doMethodTest(@NonNls final String before, @NonNls final String after) throws Exception { + public void doMethodTest(@NonNls final String before, @NonNls final String after) { doTextTest( Action.REFORMAT, "class Foo{\n" + " void foo() {\n" + before + '\n' + " }\n" + "}", @@ -212,7 +214,7 @@ public abstract class AbstractJavaFormatterTest extends LightIdeaTestCase { ); } - public void doClassTest(@NonNls final String before, @NonNls final String after) throws Exception { + public void doClassTest(@NonNls final String before, @NonNls final String after) { doTextTest( Action.REFORMAT, "class Foo{\n" + before + '\n' + "}", @@ -220,10 +222,14 @@ public abstract class AbstractJavaFormatterTest extends LightIdeaTestCase { ); } - private static String loadFile(String name) throws Exception { + private static String loadFile(String name) { String fullName = BASE_PATH + File.separatorChar + name; - String text = FileUtil.loadFile(new File(fullName)); - text = StringUtil.convertLineSeparators(text); - return text; + try { + String text = FileUtil.loadFile(new File(fullName)); + return StringUtil.convertLineSeparators(text); + } + catch (IOException e) { + throw new RuntimeException(e); + } } } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterNewLineTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterNewLineTest.java index 038b1d01f0e1..a7473f61e5a4 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterNewLineTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterNewLineTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import com.intellij.util.IncorrectOperationException; */ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { - public void testAutomaticElseWrapping() throws Exception { + public void testAutomaticElseWrapping() { getSettings().ELSE_ON_NEW_LINE = true; doMethodTest( @@ -43,7 +43,7 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { ); } - public void testAutomaticElseUnwrapping() throws Exception { + public void testAutomaticElseUnwrapping() { getSettings().ELSE_ON_NEW_LINE = false; getSettings().KEEP_LINE_BREAKS = true; @@ -60,7 +60,7 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { ); } - public void testAutomaticCatchWrapping() throws Exception { + public void testAutomaticCatchWrapping() { getSettings().CATCH_ON_NEW_LINE = true; doMethodTest( @@ -75,7 +75,7 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { ); } - public void testAutomaticCatchUnwrapping() throws Exception { + public void testAutomaticCatchUnwrapping() { getSettings().CATCH_ON_NEW_LINE = false; getSettings().KEEP_LINE_BREAKS = true; @@ -92,7 +92,7 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { ); } - public void testAutomaticFinallyWrapping() throws Exception { + public void testAutomaticFinallyWrapping() { getSettings().FINALLY_ON_NEW_LINE = true; doMethodTest( @@ -107,7 +107,7 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { ); } - public void testAutomaticFinallyUnwrapping() throws Exception { + public void testAutomaticFinallyUnwrapping() { getSettings().FINALLY_ON_NEW_LINE = false; getSettings().KEEP_LINE_BREAKS = true; @@ -124,7 +124,7 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { ); } - public void testAutomaticCatchFinallyUnwrapping() throws Exception { + public void testAutomaticCatchFinallyUnwrapping() { // Inspired by IDEA-47809 getSettings().CATCH_ON_NEW_LINE = false; getSettings().FINALLY_ON_NEW_LINE = false; @@ -144,8 +144,8 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { "}" ); } - - public void testClassInitializationBlockBracesPlacement() throws Exception { + + public void testClassInitializationBlockBracesPlacement() { // Inspired by IDEA-54191 getSettings().getRootSettings().getIndentOptions(StdFileTypes.JAVA).INDENT_SIZE = 4; getSettings().KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false; @@ -161,7 +161,7 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { ); } - public void testBlockOfMethodWithAnnotatedParameter() throws Exception { + public void testBlockOfMethodWithAnnotatedParameter() { // Inspired by IDEA-17870 doClassTest("public Test(@Qualifier(\"blah\") AType blah){}", "public Test(@Qualifier(\"blah\") AType blah) {\n" + "}"); } @@ -193,7 +193,7 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { ); } - public void testSimpleAnnotatedMethodAndBraceOnNextLineStyle() throws Exception { + public void testSimpleAnnotatedMethodAndBraceOnNextLineStyle() { // Inspired by IDEA-53542 getSettings().METHOD_BRACE_STYLE = CommonCodeStyleSettings.NEXT_LINE; getSettings().KEEP_SIMPLE_METHODS_IN_ONE_LINE = true; diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/source/tree/java/ShortenClassReferencesTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/source/tree/java/ShortenClassReferencesTest.java index e21c18022e1e..4554f93fb20d 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/source/tree/java/ShortenClassReferencesTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/source/tree/java/ShortenClassReferencesTest.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. @@ -61,6 +61,7 @@ public class ShortenClassReferencesTest extends LightCodeInsightFixtureTestCase public void testSCR37254() { doTest(); } public void testTypeAnnotatedRef() { + myFixture.configureByFile("pkg/TA.java"); doTest(); for (PsiParameter parameter : PsiTreeUtil.findChildrenOfType(myFixture.getFile(), PsiParameter.class)) { PsiTypeElement typeElement = parameter.getTypeElement(); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java index 51905419d22c..4f6c44824ab6 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.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. @@ -34,360 +34,388 @@ import java.util.HashSet; * @author dsl */ public class ChangeSignatureTest extends LightRefactoringTestCase { - public void testSimple() throws Exception { + private PsiElementFactory myFactory; + + public void setUp() throws Exception { + super.setUp(); + myFactory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); + } + + public void testSimple() { doTest(null, null, null, new ParameterInfoImpl[0], new ThrownExceptionInfo[0], false); } - public void testParameterReorder() throws Exception { + public void testParameterReorder() { doTest(null, new ParameterInfoImpl[]{new ParameterInfoImpl(1), new ParameterInfoImpl(0)}, false); } - public void testWarnAboutContract() throws Exception { + public void testWarnAboutContract() { try { doTest(null, new ParameterInfoImpl[]{new ParameterInfoImpl(1), new ParameterInfoImpl(0)}, false); fail("Conflict expected"); } - catch (BaseRefactoringProcessor.ConflictsInTestsException ignored) { - } + catch (BaseRefactoringProcessor.ConflictsInTestsException ignored) { } } - public void testGenericTypes() throws Exception { + public void testGenericTypes() { doTest(null, null, "T", new GenParams() { @Override public ParameterInfoImpl[] genParams(PsiMethod method) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); return new ParameterInfoImpl[]{ - new ParameterInfoImpl(-1, "x", factory.createTypeFromText("T", method.getParameterList()), "null"), - new ParameterInfoImpl(-1, "y", factory.createTypeFromText("C<T>", method.getParameterList()), "null") + new ParameterInfoImpl(-1, "x", myFactory.createTypeFromText("T", method.getParameterList()), "null"), + new ParameterInfoImpl(-1, "y", myFactory.createTypeFromText("C<T>", method.getParameterList()), "null") }; } }, false); } - public void testGenericTypesInOldParameters() throws Exception { + public void testGenericTypesInOldParameters() { doTest(null, null, null, new GenParams() { @Override public ParameterInfoImpl[] genParams(PsiMethod method) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); - return new ParameterInfoImpl[] { - new ParameterInfoImpl(0, "t", factory.createTypeFromText("T", method), null) + return new ParameterInfoImpl[]{ + new ParameterInfoImpl(0, "t", myFactory.createTypeFromText("T", method), null) }; } }, false); } - public void testTypeParametersInMethod() throws Exception { + public void testTypeParametersInMethod() { doTest(null, null, null, new GenParams() { - @Override - public ParameterInfoImpl[] genParams(PsiMethod method) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); - return new ParameterInfoImpl[]{ - new ParameterInfoImpl(-1, "t", factory.createTypeFromText("T", method.getParameterList()), "null"), - new ParameterInfoImpl(-1, "u", factory.createTypeFromText("U", method.getParameterList()), "null"), - new ParameterInfoImpl(-1, "cu", factory.createTypeFromText("C<U>", method.getParameterList()), "null") - }; - } - }, false); + @Override + public ParameterInfoImpl[] genParams(PsiMethod method) throws IncorrectOperationException { + return new ParameterInfoImpl[]{ + new ParameterInfoImpl(-1, "t", myFactory.createTypeFromText("T", method.getParameterList()), "null"), + new ParameterInfoImpl(-1, "u", myFactory.createTypeFromText("U", method.getParameterList()), "null"), + new ParameterInfoImpl(-1, "cu", myFactory.createTypeFromText("C<U>", method.getParameterList()), "null") + }; + } + }, false); } - public void testDefaultConstructor() throws Exception { + public void testDefaultConstructor() { doTest(null, - new ParameterInfoImpl[] { - new ParameterInfoImpl(-1, "j", PsiType.INT, "27") - }, false); + new ParameterInfoImpl[]{ + new ParameterInfoImpl(-1, "j", PsiType.INT, "27") + }, false + ); } - public void testGenerateDelegate() throws Exception { + public void testGenerateDelegate() { doTest(null, - new ParameterInfoImpl[] { + new ParameterInfoImpl[]{ new ParameterInfoImpl(-1, "i", PsiType.INT, "27") - }, true); + }, true + ); } - public void testGenerateDelegateForAbstract() throws Exception { + public void testGenerateDelegateForAbstract() { doTest(null, - new ParameterInfoImpl[] { + new ParameterInfoImpl[]{ new ParameterInfoImpl(-1, "i", PsiType.INT, "27") - }, true); + }, true + ); } - public void testGenerateDelegateWithReturn() throws Exception { + public void testGenerateDelegateWithReturn() { doTest(null, - new ParameterInfoImpl[] { + new ParameterInfoImpl[]{ new ParameterInfoImpl(-1, "i", PsiType.INT, "27") - }, true); + }, true + ); } - public void testGenerateDelegateWithParametersReordering() throws Exception { + public void testGenerateDelegateWithParametersReordering() { doTest(null, - new ParameterInfoImpl[] { + new ParameterInfoImpl[]{ new ParameterInfoImpl(1), new ParameterInfoImpl(-1, "c", PsiType.CHAR, "'a'"), new ParameterInfoImpl(0, "j", PsiType.INT) - }, true); + }, true + ); } - public void testGenerateDelegateConstructor() throws Exception { + public void testGenerateDelegateConstructor() { doTest(null, new ParameterInfoImpl[0], true); } - public void testGenerateDelegateDefaultConstructor() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testGenerateDelegateDefaultConstructor() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(-1, "i", PsiType.INT, "27") }, true); } - public void testSCR40895() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testSCR40895() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(0, "y", PsiType.INT), new ParameterInfoImpl(1, "b", PsiType.BOOLEAN) }, false); } - public void testJavadocGenericsLink() throws Exception { - doTest(null, new ParameterInfoImpl[] { - new ParameterInfoImpl(-1, "y", JavaPsiFacade.getElementFactory(getProject()).createTypeFromText("java.util.List<java.lang.String>", null)), + public void testJavadocGenericsLink() { + doTest(null, new ParameterInfoImpl[]{ + new ParameterInfoImpl(-1, "y", myFactory.createTypeFromText("java.util.List<java.lang.String>", null)), new ParameterInfoImpl(0, "a", PsiType.BOOLEAN) }, false); } - public void testParamNameSameAsFieldName() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testParamNameSameAsFieldName() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(0, "fieldName", PsiType.INT) }, false); } - public void testParamNameNoConflict() throws Exception { + public void testParamNameNoConflict() { doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(0), new ParameterInfoImpl(-1, "b", PsiType.BOOLEAN) }, false); } - public void testParamJavadoc() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testParamJavadoc() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(1, "z", PsiType.INT), new ParameterInfoImpl(0, "y", PsiType.INT) }, false); } - public void testParamJavadoc0() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testParamJavadoc0() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(1, "z", PsiType.INT), new ParameterInfoImpl(0, "y", PsiType.INT) }, false); } - public void testParamJavadoc1() throws Exception { + public void testParamJavadoc1() { doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(0, "z", PsiType.BOOLEAN) }, false); } - public void testParamJavadoc2() throws Exception { + public void testParamJavadoc2() { doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(-1, "z", PsiType.BOOLEAN), new ParameterInfoImpl(0, "a", PsiType.BOOLEAN), }, false); } - public void testJavadocNoNewLineInserted() throws Exception { + public void testJavadocNoNewLineInserted() { doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(0, "newArgs", PsiType.DOUBLE), }, false); } - public void testSuperCallFromOtherMethod() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testSuperCallFromOtherMethod() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(-1, "nnn", PsiType.INT, "-222"), }, false); } - public void testUseAnyVariable() throws Exception { + public void testUseAnyVariable() { doTest(null, null, null, new GenParams() { @Override public ParameterInfoImpl[] genParams(PsiMethod method) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); - return new ParameterInfoImpl[] { - new ParameterInfoImpl(-1, "l", factory.createTypeFromText("List", method), "null", true) + return new ParameterInfoImpl[]{ + new ParameterInfoImpl(-1, "l", myFactory.createTypeFromText("List", method), "null", true) }; } }, false); } - public void testUseThisAsAnyVariable() throws Exception { + public void testUseThisAsAnyVariable() { doTest(null, null, null, new GenParams() { @Override public ParameterInfoImpl[] genParams(PsiMethod method) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); - return new ParameterInfoImpl[] { - new ParameterInfoImpl(-1, "l", factory.createTypeFromText("List", method), "null", true) + return new ParameterInfoImpl[]{ + new ParameterInfoImpl(-1, "l", myFactory.createTypeFromText("List", method), "null", true) }; } }, false); } - public void testUseAnyVariableAndDefault() throws Exception { + public void testUseAnyVariableAndDefault() { doTest(null, null, null, new GenParams() { @Override public ParameterInfoImpl[] genParams(PsiMethod method) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); - return new ParameterInfoImpl[] { - new ParameterInfoImpl(-1, "c", factory.createTypeFromText("C", method), "null", true) + return new ParameterInfoImpl[]{ + new ParameterInfoImpl(-1, "c", myFactory.createTypeFromText("C", method), "null", true) }; } }, false); } - public void testRemoveVarargParameter() throws Exception { + public void testRemoveVarargParameter() { doTest(null, null, null, new ParameterInfoImpl[]{new ParameterInfoImpl(0)}, new ThrownExceptionInfo[0], false); } - public void testEnumConstructor() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testEnumConstructor() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(-1, "i", PsiType.INT, "10") }, false); } - public void testVarargs1() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testVarargs1() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(-1, "b", PsiType.BOOLEAN, "true"), new ParameterInfoImpl(0) }, false); } - public void testVarargs2() throws Exception { - doTest(null, new ParameterInfoImpl[] { + public void testVarargs2() { + doTest(null, new ParameterInfoImpl[]{ new ParameterInfoImpl(1, "i", PsiType.INT), new ParameterInfoImpl(0, "b", new PsiEllipsisType(PsiType.BOOLEAN)) }, false); } - public void testCovariantReturnType() throws Exception { + public void testCovariantReturnType() { doTest(CommonClassNames.JAVA_LANG_RUNNABLE, new ParameterInfoImpl[0], false); } - public void testReorderExceptions() throws Exception { + public void testReorderExceptions() { doTest(null, null, null, new SimpleParameterGen(new ParameterInfoImpl[0]), - new SimpleExceptionsGen(new ThrownExceptionInfo[]{new JavaThrownExceptionInfo(1), new JavaThrownExceptionInfo(0)}), - false); + new SimpleExceptionsGen(new ThrownExceptionInfo[]{new JavaThrownExceptionInfo(1), new JavaThrownExceptionInfo(0)}), false); } - public void testAlreadyHandled() throws Exception { + public void testAlreadyHandled() { doTest(null, null, null, new SimpleParameterGen(new ParameterInfoImpl[0]), new GenExceptions() { @Override public ThrownExceptionInfo[] genExceptions(PsiMethod method) { - return new ThrownExceptionInfo[] { - new JavaThrownExceptionInfo(-1, JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Exception", method.getResolveScope())) + return new ThrownExceptionInfo[]{ + new JavaThrownExceptionInfo(-1, myFactory.createTypeByFQClassName("java.lang.Exception", method.getResolveScope())) }; } }, - false); + false + ); } - public void testConstructorException() throws Exception { + public void testConstructorException() { doTest(null, null, null, new SimpleParameterGen(new ParameterInfoImpl[0]), new GenExceptions() { @Override public ThrownExceptionInfo[] genExceptions(PsiMethod method) { - return new ThrownExceptionInfo[] { - new JavaThrownExceptionInfo(-1, JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createTypeByFQClassName("java.io.IOException", method.getResolveScope())) + return new ThrownExceptionInfo[]{ + new JavaThrownExceptionInfo(-1, myFactory.createTypeByFQClassName("java.io.IOException", method.getResolveScope())) }; } }, - false); + false + ); } - public void testAddRuntimeException() throws Exception { + public void testAddRuntimeException() { doTest(null, null, null, new SimpleParameterGen(new ParameterInfoImpl[0]), new GenExceptions() { @Override public ThrownExceptionInfo[] genExceptions(PsiMethod method) { - return new ThrownExceptionInfo[] { - new JavaThrownExceptionInfo(-1, JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createTypeByFQClassName("java.lang.RuntimeException", method.getResolveScope())) + return new ThrownExceptionInfo[]{ + new JavaThrownExceptionInfo(-1, myFactory.createTypeByFQClassName("java.lang.RuntimeException", method.getResolveScope())) }; } }, - false); + false + ); } - public void testAddException() throws Exception { + public void testAddException() { doTest(null, null, null, new SimpleParameterGen(new ParameterInfoImpl[0]), new GenExceptions() { @Override public ThrownExceptionInfo[] genExceptions(PsiMethod method) { - return new ThrownExceptionInfo[] { - new JavaThrownExceptionInfo(-1, JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Exception", method.getResolveScope())) + return new ThrownExceptionInfo[]{ + new JavaThrownExceptionInfo(-1, myFactory.createTypeByFQClassName("java.lang.Exception", method.getResolveScope())) }; } }, - false); + false + ); } - public void testReorderWithVarargs() throws Exception { // IDEADEV-26977 - final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); - doTest(null, new ParameterInfoImpl[] { - new ParameterInfoImpl(1), - new ParameterInfoImpl(0, "s", factory.createTypeFromText("java.lang.String...", getFile())) + public void testReorderWithVarargs() { // IDEADEV-26977 + doTest(null, new ParameterInfoImpl[]{ + new ParameterInfoImpl(1), + new ParameterInfoImpl(0, "s", myFactory.createTypeFromText("java.lang.String...", getFile())) }, false); } - public void testIntroduceParameterWithDefaultValueInHierarchy() throws Exception { + public void testIntroduceParameterWithDefaultValueInHierarchy() { doTest(null, new ParameterInfoImpl[]{new ParameterInfoImpl(-1, "i", PsiType.INT, "0")}, false); } - public void testReorderMultilineMethodParameters() throws Exception { + public void testReorderMultilineMethodParameters() { // Inspired by IDEA-54902 - doTest(null, new ParameterInfoImpl[] {new ParameterInfoImpl(1), new ParameterInfoImpl(0)}, false); + doTest(null, new ParameterInfoImpl[]{new ParameterInfoImpl(1), new ParameterInfoImpl(0)}, false); } - public void testRemoveFirstParameter() throws Exception { + public void testRemoveFirstParameter() { doTest(null, new ParameterInfoImpl[]{new ParameterInfoImpl(1)}, false); } - public void testReplaceVarargWithArray() throws Exception { + public void testReplaceVarargWithArray() { doTest(null, null, null, new GenParams() { @Override public ParameterInfoImpl[] genParams(PsiMethod method) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); - return new ParameterInfoImpl[] { - new ParameterInfoImpl(1, "l", factory.createTypeFromText("List<T>[]", method.getParameterList()), "null", false), - new ParameterInfoImpl(0, "s", factory.createTypeFromText("String", method.getParameterList())) + return new ParameterInfoImpl[]{ + new ParameterInfoImpl(1, "l", myFactory.createTypeFromText("List<T>[]", method.getParameterList()), "null", false), + new ParameterInfoImpl(0, "s", myFactory.createTypeFromText("String", method.getParameterList())) }; } }, false); } - public void testMethodParametersAlignmentAfterMethodNameChange() throws Exception { + public void testMethodParametersAlignmentAfterMethodNameChange() { getCurrentCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS = true; getCurrentCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; doTest(null, "test123asd", null, new SimpleParameterGen(), new SimpleExceptionsGen(), false); } - public void testMethodParametersAlignmentAfterMethodVisibilityChange() throws Exception { + public void testMethodParametersAlignmentAfterMethodVisibilityChange() { getCurrentCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS = true; getCurrentCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; doTest(PsiModifier.PROTECTED, null, null, new SimpleParameterGen(), new SimpleExceptionsGen(), false); } - public void testMethodParametersAlignmentAfterMethodReturnTypeChange() throws Exception { + public void testMethodParametersAlignmentAfterMethodReturnTypeChange() { getCurrentCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS = true; getCurrentCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; doTest(null, null, "Exception", new SimpleParameterGen(), new SimpleExceptionsGen(), false); } - public void testVisibilityOfOverriddenMethod() throws Exception { + public void testVisibilityOfOverriddenMethod() { doTest(PsiModifier.PACKAGE_LOCAL, "foo", "void", new ParameterInfoImpl[0], new ThrownExceptionInfo[0], false); } - public void testRemoveExceptions() throws Exception { + public void testRemoveExceptions() { doTest(null, null, "void", new SimpleParameterGen(), new SimpleExceptionsGen(), false); } - private void doTest(@Nullable String newReturnType, - ParameterInfoImpl[] parameterInfos, - final boolean generateDelegate) throws Exception { + public void testPropagateParameter() { + String basePath = "/refactoring/changeSignature/" + getTestName(false); + configureByFile(basePath + ".java"); + final PsiElement targetElement = TargetElementUtilBase.findTargetElement(getEditor(), TargetElementUtilBase.ELEMENT_NAME_ACCEPTED); + assertTrue("<caret> is not on method name", targetElement instanceof PsiMethod); + PsiMethod method = (PsiMethod)targetElement; + final PsiClass containingClass = method.getContainingClass(); + assertTrue(containingClass != null); + final PsiMethod[] callers = containingClass.findMethodsByName("caller", false); + assertTrue(callers.length > 0); + final PsiMethod caller = callers[0]; + final HashSet<PsiMethod> propagateParametersMethods = new HashSet<PsiMethod>(); + propagateParametersMethods.add(caller); + final PsiParameter[] parameters = method.getParameterList().getParameters(); + new ChangeSignatureProcessor(getProject(), method, false, null, method.getName(), + CanonicalTypes.createTypeWrapper(PsiType.VOID), new ParameterInfoImpl[]{ + new ParameterInfoImpl(0, parameters[0].getName(), parameters[0].getType()), + new ParameterInfoImpl(-1, "b", PsiType.BOOLEAN)}, null, propagateParametersMethods, null + ).run(); + checkResultByFile(basePath + "_after.java"); + } + + /* workers */ + + private void doTest(@Nullable String newReturnType, ParameterInfoImpl[] parameterInfos, boolean generateDelegate) { doTest(null, null, newReturnType, parameterInfos, new ThrownExceptionInfo[0], generateDelegate); } @@ -396,14 +424,15 @@ public class ChangeSignatureTest extends LightRefactoringTestCase { @Nullable String newReturnType, ParameterInfoImpl[] parameterInfo, ThrownExceptionInfo[] exceptionInfo, - final boolean generateDelegate) throws Exception { + boolean generateDelegate) { doTest(newVisibility, newName, newReturnType, new SimpleParameterGen(parameterInfo), new SimpleExceptionsGen(exceptionInfo), generateDelegate); } private void doTest(@PsiModifier.ModifierConstant @Nullable String newVisibility, @Nullable String newName, @Nullable @NonNls String newReturnType, - GenParams gen, final boolean generateDelegate) throws Exception { + GenParams gen, + boolean generateDelegate) { doTest(newVisibility, newName, newReturnType, gen, new SimpleExceptionsGen(), generateDelegate); } @@ -412,45 +441,17 @@ public class ChangeSignatureTest extends LightRefactoringTestCase { @Nullable String newReturnType, GenParams genParams, GenExceptions genExceptions, - final boolean generateDelegate) throws Exception { + boolean generateDelegate) { String basePath = "/refactoring/changeSignature/" + getTestName(false); - @NonNls final String filePath = basePath + ".java"; - configureByFile(filePath); - final PsiElement targetElement = TargetElementUtilBase.findTargetElement(getEditor(), TargetElementUtilBase.ELEMENT_NAME_ACCEPTED); + configureByFile(basePath + ".java"); + PsiElement targetElement = TargetElementUtilBase.findTargetElement(getEditor(), TargetElementUtilBase.ELEMENT_NAME_ACCEPTED); assertTrue("<caret> is not on method name", targetElement instanceof PsiMethod); - PsiMethod method = (PsiMethod) targetElement; - final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); - PsiType newType = newReturnType != null ? factory.createTypeFromText(newReturnType, method) : method.getReturnType(); + PsiMethod method = (PsiMethod)targetElement; + PsiType newType = newReturnType != null ? myFactory.createTypeFromText(newReturnType, method) : method.getReturnType(); new ChangeSignatureProcessor(getProject(), method, generateDelegate, newVisibility, newName != null ? newName : method.getName(), newType, genParams.genParams(method), genExceptions.genExceptions(method)).run(); - @NonNls String after = basePath + "_after.java"; - checkResultByFile(after); - } - - public void testPropagateParameter() throws Exception { - String basePath = "/refactoring/changeSignature/" + getTestName(false); - @NonNls final String filePath = basePath + ".java"; - configureByFile(filePath); - final PsiElement targetElement = TargetElementUtilBase.findTargetElement(getEditor(), TargetElementUtilBase.ELEMENT_NAME_ACCEPTED); - assertTrue("<caret> is not on method name", targetElement instanceof PsiMethod); - PsiMethod method = (PsiMethod) targetElement; - final PsiClass containingClass = method.getContainingClass(); - assertTrue(containingClass != null); - final PsiMethod[] callers = containingClass.findMethodsByName("caller", false); - assertTrue(callers.length > 0); - final PsiMethod caller = callers[0]; - final HashSet<PsiMethod> propagateParametersMethods = new HashSet<PsiMethod>(); - propagateParametersMethods.add(caller); - final PsiParameter[] parameters = method.getParameterList().getParameters(); - new ChangeSignatureProcessor(getProject(), method, false, null, - method.getName(), - CanonicalTypes.createTypeWrapper(PsiType.VOID), new ParameterInfoImpl[]{ - new ParameterInfoImpl(0, parameters[0].getName(), parameters[0].getType()), - new ParameterInfoImpl(-1, "b", PsiType.BOOLEAN)}, null, - propagateParametersMethods, null).run(); - @NonNls String after = basePath + "_after.java"; - checkResultByFile(after); + checkResultByFile(basePath + "_after.java"); } private interface GenParams { @@ -460,8 +461,7 @@ public class ChangeSignatureTest extends LightRefactoringTestCase { private static class SimpleParameterGen implements GenParams { private ParameterInfoImpl[] myInfos; - private SimpleParameterGen() { - } + private SimpleParameterGen() { } private SimpleParameterGen(ParameterInfoImpl[] infos) { myInfos = infos; diff --git a/java/openapi/src/com/intellij/ui/classFilter/ClassFilter.java b/java/openapi/src/com/intellij/ui/classFilter/ClassFilter.java index 2749c340c695..7521d3bd7c13 100644 --- a/java/openapi/src/com/intellij/ui/classFilter/ClassFilter.java +++ b/java/openapi/src/com/intellij/ui/classFilter/ClassFilter.java @@ -21,16 +21,22 @@ import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.util.xmlb.annotations.Transient; import org.jdom.Element; import java.util.regex.Matcher; import java.util.regex.Pattern; +@Tag("class-filter") public class ClassFilter implements JDOMExternalizable, Cloneable{ private static final Logger LOG = Logger.getInstance("#com.intellij.ui.classFilter.ClassFilter"); public static final ClassFilter[] EMPTY_ARRAY = new ClassFilter[0]; + @Attribute("pattern") public String PATTERN = ""; + @Attribute("enabled") public boolean ENABLED = true; private Matcher myMatcher; // to speedup matching @@ -42,9 +48,12 @@ public class ClassFilter implements JDOMExternalizable, Cloneable{ ENABLED = true; } + @Transient public String getPattern() { return PATTERN; } + + @Transient public boolean isEnabled() { return ENABLED; } diff --git a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java index 26e0eb52d34a..d7dfea857ba9 100644 --- a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java +++ b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java @@ -311,26 +311,26 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa String suspendPolicy = readValue(comment, "suspendPolicy"); if (suspendPolicy != null) { - breakpoint.SUSPEND = !DebuggerSettings.SUSPEND_NONE.equals(suspendPolicy); - breakpoint.SUSPEND_POLICY = suspendPolicy; + //breakpoint.setSuspend(!DebuggerSettings.SUSPEND_NONE.equals(suspendPolicy)); + breakpoint.setSuspendPolicy(suspendPolicy); println("SUSPEND_POLICY = " + suspendPolicy, ProcessOutputTypes.SYSTEM); } String condition = readValue(comment, "Condition"); if (condition != null) { - breakpoint.CONDITION_ENABLED = true; + //breakpoint.CONDITION_ENABLED = true; breakpoint.setCondition(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, condition)); println("Condition = " + condition, ProcessOutputTypes.SYSTEM); } String passCount = readValue(comment, "Pass count"); if (passCount != null) { - breakpoint.COUNT_FILTER_ENABLED = true; - breakpoint.COUNT_FILTER = Integer.parseInt(passCount); + breakpoint.setCountFilterEnabled(true); + breakpoint.setCountFilter(Integer.parseInt(passCount)); println("Pass count = " + passCount, ProcessOutputTypes.SYSTEM); } String classFilters = readValue(comment, "Class filters"); if (classFilters != null) { - breakpoint.CLASS_FILTERS_ENABLED = true; + breakpoint.setClassFiltersEnabled(true); StringTokenizer tokenizer = new StringTokenizer(classFilters, " ,"); ArrayList<ClassFilter> lst = new ArrayList<ClassFilter>(); diff --git a/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java b/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java index f6f140049f21..5930288f2c2c 100644 --- a/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; public abstract class ModuleTestCase extends IdeaTestCase { protected final Collection<Module> myModulesToDispose = new ArrayList<Module>(); @@ -100,6 +101,7 @@ public abstract class ModuleTestCase extends IdeaTestCase { @Override public Module compute() { try { + LocalFileSystem.getInstance().refreshIoFiles(Collections.singletonList(moduleFile)); return ModuleManager.getInstance(myProject).loadModule(moduleFile.getAbsolutePath()); } catch (Exception e) { @@ -162,6 +164,7 @@ public abstract class ModuleTestCase extends IdeaTestCase { FileUtil.copyDir(dirInTestDataFile, moduleDir); final Module module = createModule(moduleDir + "/" + newModuleFileName, moduleType); final VirtualFile root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(moduleDir); + assertNotNull(root); new WriteCommandAction.Simple(module.getProject()) { @Override protected void run() throws Throwable { diff --git a/jps/jps-builders/jps-builders.iml b/jps/jps-builders/jps-builders.iml index fea80a020e80..9dd56d591d6e 100644 --- a/jps/jps-builders/jps-builders.iml +++ b/jps/jps-builders/jps-builders.iml @@ -36,6 +36,7 @@ <orderEntry type="module" module-name="jps-model-serialization" /> <orderEntry type="module" module-name="jps-model-impl" /> <orderEntry type="library" scope="TEST" name="Groovy" level="project" /> + <orderEntry type="module" module-name="jps-serialization-tests" scope="TEST" /> </component> </module> diff --git a/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.builders.java.JavaCompilingTool b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.builders.java.JavaCompilingTool new file mode 100644 index 000000000000..f26b04843daf --- /dev/null +++ b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.builders.java.JavaCompilingTool @@ -0,0 +1,2 @@ +org.jetbrains.jps.builders.impl.java.JavacCompilerTool +org.jetbrains.jps.builders.impl.java.EclipseCompilerTool
\ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/ModuleChunk.java b/jps/jps-builders/src/org/jetbrains/jps/ModuleChunk.java index 683a8b02abb0..5f74fa20db0d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/ModuleChunk.java +++ b/jps/jps-builders/src/org/jetbrains/jps/ModuleChunk.java @@ -50,6 +50,21 @@ public class ModuleChunk { myContainsTests = containsTests; } + public String getPresentableShortName() { + String name = myModules.iterator().next().getName(); + if (myModules.size() > 1) { + name += " and " + (myModules.size() - 1) + " more"; + String fullName = getName(); + if (fullName.length() < name.length()) { + name = fullName; + } + } + if (containsTests()) { + name = "tests of " + name; + } + return name; + } + public String getName() { if (myModules.size() == 1) return myModules.iterator().next().getName(); return StringUtil.join(myModules, GET_NAME, ","); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/EclipseCompilerTool.java b/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/EclipseCompilerTool.java new file mode 100644 index 000000000000..bea32c02b013 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/EclipseCompilerTool.java @@ -0,0 +1,94 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jps.builders.impl.java; + +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.java.CannotCreateJavaCompilerException; +import org.jetbrains.jps.builders.java.JavaCompilingTool; +import org.jetbrains.jps.cmdline.ClasspathBootstrap; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.incremental.Utils; +import org.jetbrains.jps.model.java.compiler.JavaCompilers; + +import javax.tools.*; +import java.io.File; +import java.util.Collections; +import java.util.List; +import java.util.ServiceLoader; + +/** + * @author nik + */ +public class EclipseCompilerTool extends JavaCompilingTool { + @NotNull + @Override + public String getId() { + return JavaCompilers.ECLIPSE_ID; + } + + @Nullable + @Override + public String getAlternativeId() { + return JavaCompilers.ECLIPSE_EMBEDDED_ID; + } + + @NotNull + @Override + public String getDescription() { + return "Eclipse compiler"; + } + + @NotNull + @Override + public JavaCompiler createCompiler() throws CannotCreateJavaCompilerException { + for (JavaCompiler javaCompiler : ServiceLoader.load(JavaCompiler.class)) { + if ("EclipseCompiler".equals(StringUtil.getShortName(javaCompiler.getClass()))) { + return javaCompiler; + } + } + throw new CannotCreateJavaCompilerException("Eclipse Batch Compiler was not found in classpath"); + } + + @NotNull + @Override + public List<File> getAdditionalClasspath() { + for (JavaCompiler javaCompiler : ServiceLoader.load(JavaCompiler.class)) { // Eclipse compiler + final File compilerResource = ClasspathBootstrap.getResourceFile(javaCompiler.getClass()); + final String name = compilerResource.getName(); + if (name.startsWith("ecj-") && name.endsWith(".jar")) { + return Collections.singletonList(compilerResource); + } + } + return Collections.emptyList(); + } + + @Override + public void processCompilerOptions(@NotNull CompileContext context, @NotNull List<String> options) { + for (String option : options) { + if (option.startsWith("-proceedOnError")) { + Utils.PROCEED_ON_ERROR_KEY.set(context, Boolean.TRUE); + break; + } + } + } + + @Override + public List<String> getDefaultCompilerOptions() { + return Collections.singletonList("-noExit"); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/JavacCompilerTool.java b/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/JavacCompilerTool.java new file mode 100644 index 000000000000..976e750fe15d --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/JavacCompilerTool.java @@ -0,0 +1,82 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jps.builders.impl.java; + +import com.intellij.util.ExceptionUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.java.CannotCreateJavaCompilerException; +import org.jetbrains.jps.builders.java.JavaCompilingTool; +import org.jetbrains.jps.javac.JavacMain; +import org.jetbrains.jps.model.java.compiler.JavaCompilers; + +import javax.tools.*; +import java.io.File; +import java.util.Collections; +import java.util.List; + +/** + * @author nik + */ +public class JavacCompilerTool extends JavaCompilingTool { + @NotNull + @Override + public String getId() { + return JavaCompilers.JAVAC_ID; + } + + @Nullable + @Override + public String getAlternativeId() { + return JavaCompilers.JAVAC_API_ID; + } + + @NotNull + @Override + public String getDescription() { + return "javac " + System.getProperty("java.version"); + } + + @NotNull + @Override + public JavaCompiler createCompiler() throws CannotCreateJavaCompilerException { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + if (compiler != null) { + return compiler; + } + + String message = "System Java Compiler was not found in classpath"; + // trying to obtain additional diagnostic for the case when compiler.jar is present, but there were problems with compiler class loading: + try { + Class.forName("com.sun.tools.javac.api.JavacTool", false, JavacMain.class.getClassLoader()); + } + catch (Throwable ex) { + message = message + ":\n" + ExceptionUtil.getThrowableText(ex); + } + throw new CannotCreateJavaCompilerException(message); + } + + @NotNull + @Override + public List<File> getAdditionalClasspath() { + return Collections.emptyList(); + } + + @Override + public List<String> getDefaultCompilerOptions() { + return Collections.singletonList("-implicit:class"); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/CannotCreateJavaCompilerException.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/CannotCreateJavaCompilerException.java new file mode 100644 index 000000000000..4901a970f3a7 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/CannotCreateJavaCompilerException.java @@ -0,0 +1,25 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jps.builders.java; + +/** + * @author nik + */ +public class CannotCreateJavaCompilerException extends Exception { + public CannotCreateJavaCompilerException(String message) { + super(message); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java index 35de6680ca87..1f0cd41c7ffa 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.ModuleChunk; import org.jetbrains.jps.ProjectPaths; import org.jetbrains.jps.builders.BuildRootIndex; @@ -38,6 +39,7 @@ import org.jetbrains.jps.model.library.JpsTypedLibrary; import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.model.library.sdk.JpsSdkReference; import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.service.JpsServiceManager; import java.io.File; import java.io.IOException; @@ -79,7 +81,7 @@ public class JavaBuilderUtil { final boolean errorsDetected = Utils.errorsDetected(context); if (!isForcedRecompilationAllJavaModules(context)) { if (context.shouldDifferentiate(chunk)) { - context.processMessage(new ProgressMessage("Checking dependencies... [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage("Checking dependencies... [" + chunk.getPresentableShortName() + "]")); final Set<File> allCompiledFiles = getAllCompiledFilesContainer(context); final Set<File> allAffectedFiles = getAllAffectedFilesContainer(context); @@ -144,7 +146,7 @@ public class JavaBuilderUtil { } } else { - final String messageText = "Marking " + chunk.getName() + " and direct dependants for recompilation"; + final String messageText = "Marking " + chunk.getPresentableShortName() + " and direct dependants for recompilation"; LOG.info("Non-incremental mode: " + messageText); context.processMessage(new ProgressMessage(messageText)); @@ -172,7 +174,7 @@ public class JavaBuilderUtil { return false; } - context.processMessage(new ProgressMessage("Updating dependency information... [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage("Updating dependency information... [" + chunk.getPresentableShortName() + "]")); globalMappings.integrate(delta); @@ -281,6 +283,16 @@ public class JavaBuilderUtil { return sdkLibrary.getProperties(); } + @Nullable + public static JavaCompilingTool findCompilingTool(@NotNull String compilerId) { + for (JavaCompilingTool tool : JpsServiceManager.getInstance().getExtensions(JavaCompilingTool.class)) { + if (compilerId.equals(tool.getId()) || compilerId.equals(tool.getAlternativeId())) { + return tool; + } + } + return null; + } + private static class ModulesBasedFileFilter implements Mappings.DependentFilesFilter { private final CompileContext myContext; private final Set<JpsModule> myChunkModules; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaCompilingTool.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaCompilingTool.java new file mode 100644 index 000000000000..6728cf3c4a20 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaCompilingTool.java @@ -0,0 +1,58 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jps.builders.java; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.incremental.CompileContext; + +import javax.tools.*; +import java.io.File; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author nik + */ +public abstract class JavaCompilingTool { + @NotNull + public abstract String getId(); + + @Nullable + public String getAlternativeId() { + return null; + } + + @NotNull + public abstract String getDescription(); + + @NotNull + public abstract JavaCompiler createCompiler() throws CannotCreateJavaCompilerException; + + @NotNull + public abstract List<File> getAdditionalClasspath(); + + public void processCompilerOptions(@NotNull CompileContext context, @NotNull List<String> options) { + } + + public void prepareCompilationTask(@NotNull JavaCompiler.CompilationTask task, @NotNull Collection<String> options) { + } + + public List<String> getDefaultCompilerOptions() { + return Collections.emptyList(); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java index e104ffd7e630..21818f540cc7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -380,12 +380,12 @@ public class ClassRepr extends Proto { public static DataExternalizer<ClassRepr> externalizer(final DependencyContext context) { return new DataExternalizer<ClassRepr>() { @Override - public void save(final DataOutput out, final ClassRepr value) throws IOException { + public void save(@NotNull final DataOutput out, final ClassRepr value) throws IOException { value.save(out); } @Override - public ClassRepr read(final DataInput in) throws IOException { + public ClassRepr read(@NotNull final DataInput in) throws IOException { return new ClassRepr(context, in); } }; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/FieldRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/FieldRepr.java index b72e5aa18d5b..92359612f034 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/FieldRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/FieldRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.jetbrains.jps.builders.java.dependencyView; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -57,12 +58,12 @@ class FieldRepr extends ProtoMember { public static DataExternalizer<FieldRepr> externalizer(final DependencyContext context) { return new DataExternalizer<FieldRepr>() { @Override - public void save(final DataOutput out, final FieldRepr value) throws IOException { + public void save(@NotNull final DataOutput out, final FieldRepr value) throws IOException { value.save(out); } @Override - public FieldRepr read(final DataInput in) throws IOException { + public FieldRepr read(@NotNull final DataInput in) throws IOException { return new FieldRepr(context, in); } }; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntIntPersistentMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntIntPersistentMultiMaplet.java index eb94639941ac..560c4cecc0fd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntIntPersistentMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntIntPersistentMultiMaplet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -256,7 +256,7 @@ class IntIntPersistentMultiMaplet extends IntIntMultiMaplet { private static class IntSetExternalizer implements DataExternalizer<TIntHashSet> { @Override - public void save(final DataOutput out, final TIntHashSet value) throws IOException { + public void save(@NotNull final DataOutput out, final TIntHashSet value) throws IOException { final Ref<IOException> exRef = new Ref<IOException>(null); value.forEach(new TIntProcedure() { @Override @@ -278,7 +278,7 @@ class IntIntPersistentMultiMaplet extends IntIntMultiMaplet { } @Override - public TIntHashSet read(final DataInput in) throws IOException { + public TIntHashSet read(@NotNull final DataInput in) throws IOException { final TIntHashSet result = new TIntHashSet(); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntObjectPersistentMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntObjectPersistentMultiMaplet.java index d195cbc4fc6f..3dd4d446c99a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntObjectPersistentMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/IntObjectPersistentMultiMaplet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -245,14 +245,14 @@ class IntObjectPersistentMultiMaplet<V extends Streamable> extends IntObjectMult } @Override - public void save(final DataOutput out, final Collection<V> value) throws IOException { + public void save(@NotNull final DataOutput out, final Collection<V> value) throws IOException { for (V x : value) { myElementExternalizer.save(out, x); } } @Override - public Collection<V> read(final DataInput in) throws IOException { + public Collection<V> read(@NotNull final DataInput in) throws IOException { final Collection<V> result = myCollectionFactory.create(); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java index 7b55ea7aaa29..72ad7557cd0b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.jetbrains.jps.builders.java.dependencyView; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Type; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; @@ -159,12 +160,12 @@ class MethodRepr extends ProtoMember { public static DataExternalizer<MethodRepr> externalizer(final DependencyContext context) { return new DataExternalizer<MethodRepr>() { @Override - public void save(final DataOutput out, final MethodRepr value) throws IOException { + public void save(@NotNull final DataOutput out, final MethodRepr value) throws IOException { value.save(out); } @Override - public MethodRepr read(DataInput in) throws IOException { + public MethodRepr read(@NotNull DataInput in) throws IOException { return new MethodRepr(context, in); } }; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ObjectObjectPersistentMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ObjectObjectPersistentMultiMaplet.java index d94d092b13d1..26a9b7a5756f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ObjectObjectPersistentMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ObjectObjectPersistentMultiMaplet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -245,14 +245,14 @@ public class ObjectObjectPersistentMultiMaplet<K, V extends Streamable> extends } @Override - public void save(final DataOutput out, final Collection<V> value) throws IOException { + public void save(@NotNull final DataOutput out, final Collection<V> value) throws IOException { for (V x : value) { myElementExternalizer.save(out, x); } } @Override - public Collection<V> read(final DataInput in) throws IOException { + public Collection<V> read(@NotNull final DataInput in) throws IOException { final Collection<V> result = myCollectionFactory.create(); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/TypeRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/TypeRepr.java index dbdb7a9f1179..af85d75f344f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/TypeRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/TypeRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.jetbrains.jps.builders.java.dependencyView; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Type; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; @@ -280,12 +281,12 @@ class TypeRepr { public static DataExternalizer<AbstractType> externalizer(final DependencyContext context) { return new DataExternalizer<AbstractType>() { @Override - public void save(final DataOutput out, final AbstractType value) throws IOException { + public void save(@NotNull final DataOutput out, final AbstractType value) throws IOException { value.save(out); } @Override - public AbstractType read(final DataInput in) throws IOException { + public AbstractType read(@NotNull final DataInput in) throws IOException { AbstractType elementType; int level = 0; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java index 8db8bbc11ec4..a6b6bdd143f5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.TIntHashSet; import gnu.trove.TIntProcedure; +import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Type; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; @@ -505,12 +506,12 @@ class UsageRepr { public static class AnnotationUsage extends Usage { public static final DataExternalizer<ElemType> elementTypeExternalizer = new DataExternalizer<ElemType>() { @Override - public void save(final DataOutput out, final ElemType value) throws IOException { + public void save(@NotNull final DataOutput out, final ElemType value) throws IOException { DataInputOutputUtil.writeINT(out, value.ordinal()); } @Override - public ElemType read(final DataInput in) throws IOException { + public ElemType read(@NotNull final DataInput in) throws IOException { final int ordinal = DataInputOutputUtil.readINT(in); for (ElemType value : ElemType.values()) { if (value.ordinal() == ordinal) { @@ -699,12 +700,12 @@ class UsageRepr { public static DataExternalizer<Usage> externalizer(final DependencyContext context) { return new DataExternalizer<Usage>() { @Override - public void save(final DataOutput out, final Usage value) throws IOException { + public void save(@NotNull final DataOutput out, final Usage value) throws IOException { value.save(out); } @Override - public Usage read(DataInput in) throws IOException { + public Usage read(@NotNull DataInput in) throws IOException { final byte tag = in.readByte(); switch (tag) { case CLASS_USAGE: diff --git a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/TObjectIntHashMapExternalizer.java b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/TObjectIntHashMapExternalizer.java index c75414079b86..eed818e08567 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/TObjectIntHashMapExternalizer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/TObjectIntHashMapExternalizer.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. @@ -18,6 +18,7 @@ package org.jetbrains.jps.classFilesIndex; import com.intellij.util.io.DataExternalizer; import gnu.trove.TObjectIntHashMap; import gnu.trove.TObjectIntProcedure; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -34,7 +35,7 @@ public class TObjectIntHashMapExternalizer<K> implements DataExternalizer<TObjec } @Override - public void save(final DataOutput out, final TObjectIntHashMap<K> map) throws IOException { + public void save(@NotNull final DataOutput out, final TObjectIntHashMap<K> map) throws IOException { out.writeInt(map.size()); try { map.forEachEntry(new TObjectIntProcedure<K>() { @@ -57,7 +58,7 @@ public class TObjectIntHashMapExternalizer<K> implements DataExternalizer<TObjec } @Override - public TObjectIntHashMap<K> read(final DataInput in) throws IOException { + public TObjectIntHashMap<K> read(@NotNull final DataInput in) throws IOException { final int size = in.readInt(); final TObjectIntHashMap<K> map = new TObjectIntHashMap<K>(size); for (int i = 0; i < size; i++) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/api/storage/ClassFilesIndexStorageBase.java b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/api/storage/ClassFilesIndexStorageBase.java index 4d2b60446b52..1eba7b5f9512 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/api/storage/ClassFilesIndexStorageBase.java +++ b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/api/storage/ClassFilesIndexStorageBase.java @@ -163,7 +163,7 @@ public class ClassFilesIndexStorageBase<K, V> { private static <V> DataExternalizer<CompiledDataValueContainer<V>> createValueContainerExternalizer(final DataExternalizer<V> valueExternalizer) { return new DataExternalizer<CompiledDataValueContainer<V>>() { @Override - public void save(final DataOutput out, final CompiledDataValueContainer<V> value) throws IOException { + public void save(@NotNull final DataOutput out, final CompiledDataValueContainer<V> value) throws IOException { final TIntObjectHashMap<V> underlying = value.myUnderlying; out.writeInt(underlying.size()); final IOException[] ioException = {null}; @@ -187,7 +187,7 @@ public class ClassFilesIndexStorageBase<K, V> { } @Override - public CompiledDataValueContainer<V> read(final DataInput in) throws IOException { + public CompiledDataValueContainer<V> read(@NotNull final DataInput in) throws IOException { final TIntObjectHashMap<V> map = new TIntObjectHashMap<V>(); final int size = in.readInt(); for (int i = 0; i < size; i++) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/impl/EnumeratedMethodIncompleteSignature.java b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/impl/EnumeratedMethodIncompleteSignature.java index fec5e9acccd7..b93a7da728f5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/impl/EnumeratedMethodIncompleteSignature.java +++ b/jps/jps-builders/src/org/jetbrains/jps/classFilesIndex/indexer/impl/EnumeratedMethodIncompleteSignature.java @@ -53,14 +53,14 @@ public class EnumeratedMethodIncompleteSignature { public static DataExternalizer<EnumeratedMethodIncompleteSignature> createDataExternalizer() { return new DataExternalizer<EnumeratedMethodIncompleteSignature>() { @Override - public void save(final DataOutput out, final EnumeratedMethodIncompleteSignature value) throws IOException { + public void save(@NotNull final DataOutput out, final EnumeratedMethodIncompleteSignature value) throws IOException { out.writeInt(value.getOwner()); out.writeInt(value.getName()); out.writeBoolean(value.isStatic()); } @Override - public EnumeratedMethodIncompleteSignature read(final DataInput in) throws IOException { + public EnumeratedMethodIncompleteSignature read(@NotNull final DataInput in) throws IOException { return new EnumeratedMethodIncompleteSignature(in.readInt(), in.readInt(), in.readBoolean()); diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java index d2b4c7f3210b..c89cb50397fb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java @@ -32,15 +32,14 @@ import net.n3.nanoxml.IXMLBuilder; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.ClassVisitor; import org.jetbrains.asm4.ClassWriter; +import org.jetbrains.jps.builders.java.JavaCompilingTool; import org.jetbrains.jps.builders.java.JavaSourceTransformer; import org.jetbrains.jps.javac.JavacServer; import org.jetbrains.jps.model.JpsModel; import org.jetbrains.jps.model.impl.JpsModelImpl; import org.jetbrains.jps.model.serialization.JpsProjectLoader; -import javax.tools.JavaCompiler; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; +import javax.tools.*; import java.io.File; import java.lang.reflect.Method; import java.util.*; @@ -177,7 +176,7 @@ public class ClasspathBootstrap { } } - public static List<File> getJavacServerClasspath(String sdkHome, boolean useEclipseCompiler) { + public static List<File> getJavacServerClasspath(String sdkHome, JavaCompilingTool compilingTool) { final Set<File> cp = new LinkedHashSet<File>(); cp.add(getResourceFile(JavacServer.class)); // self // util @@ -236,16 +235,7 @@ public class ClasspathBootstrap { } } - if (useEclipseCompiler) { - // eclipse compiler - for (JavaCompiler javaCompiler : ServiceLoader.load(JavaCompiler.class)) { // Eclipse compiler - final File compilerResource = getResourceFile(javaCompiler.getClass()); - final String name = compilerResource.getName(); - if (name.startsWith("ecj-") && name.endsWith(".jar")) { - cp.add(compilerResource); - } - } - } + cp.addAll(compilingTool.getAdditionalClasspath()); final Class<JavaSourceTransformer> transformerClass = JavaSourceTransformer.class; final ServiceLoader<JavaSourceTransformer> loader = ServiceLoader.load(transformerClass, transformerClass.getClassLoader()); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactOutputToSourceMapping.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactOutputToSourceMapping.java index 572433552d65..fa022448ef73 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactOutputToSourceMapping.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactOutputToSourceMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import com.intellij.util.SmartList; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.IOUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.incremental.storage.AbstractStateStorage; import org.jetbrains.jps.incremental.storage.PathStringDescriptor; @@ -85,7 +86,7 @@ public class ArtifactOutputToSourceMapping extends AbstractStateStorage<String, private final byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, List<SourcePathAndRootIndex> value) throws IOException { + public void save(@NotNull DataOutput out, List<SourcePathAndRootIndex> value) throws IOException { for (SourcePathAndRootIndex pair : value) { IOUtil.writeUTFFast(myBuffer, out, pair.myPath); out.writeInt(pair.getRootIndex()); @@ -93,7 +94,7 @@ public class ArtifactOutputToSourceMapping extends AbstractStateStorage<String, } @Override - public List<SourcePathAndRootIndex> read(DataInput in) throws IOException { + public List<SourcePathAndRootIndex> read(@NotNull DataInput in) throws IOException { List<SourcePathAndRootIndex> result = new SmartList<SourcePathAndRootIndex>(); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/ClassProcessingBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/ClassProcessingBuilder.java index 092b002f2384..af1c974b84a2 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/ClassProcessingBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/ClassProcessingBuilder.java @@ -74,7 +74,7 @@ public abstract class ClassProcessingBuilder extends ModuleLevelBuilder { final String progress = getProgressMessage(); final boolean shouldShowProgress = !StringUtil.isEmptyOrSpaces(progress); if (shouldShowProgress) { - context.processMessage(new ProgressMessage(progress + " [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage(progress + " [" + chunk.getPresentableShortName() + "]")); } ExitCode exitCode = ExitCode.NOTHING_DONE; diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 645cdd648bbb..db1700c47cbd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -39,6 +39,7 @@ import org.jetbrains.jps.builders.DirtyFilesHolder; import org.jetbrains.jps.builders.FileProcessor; import org.jetbrains.jps.builders.java.JavaBuilderExtension; import org.jetbrains.jps.builders.java.JavaBuilderUtil; +import org.jetbrains.jps.builders.java.JavaCompilingTool; import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; import org.jetbrains.jps.builders.java.dependencyView.Callbacks; import org.jetbrains.jps.builders.java.dependencyView.Mappings; @@ -81,7 +82,7 @@ public class JavaBuilder extends ModuleLevelBuilder { public static final boolean USE_EMBEDDED_JAVAC = System.getProperty(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null; private static final Key<Integer> JAVA_COMPILER_VERSION_KEY = Key.create("_java_compiler_version_"); public static final Key<Boolean> IS_ENABLED = Key.create("_java_compiler_enabled_"); - private static final Key<Boolean> IS_COMPILER_API_SUPPORTED = Key.create("_java_compiler_api_supported_"); + private static final Key<JavaCompilingTool> COMPILING_TOOL = Key.create("_java_compiling_tool_"); private static final Key<AtomicReference<String>> COMPILER_VERSION_INFO = Key.create("_java_compiler_version_info_"); private static final Set<String> FILTERED_OPTIONS = new HashSet<String>(Arrays.<String>asList( @@ -137,16 +138,9 @@ public class JavaBuilder extends ModuleLevelBuilder { if (LOG.isDebugEnabled()) { LOG.debug("Java compiler ID: " + compilerId); } - final boolean isJavac = JavaCompilers.JAVAC_ID.equalsIgnoreCase(compilerId) || JavaCompilers.JAVAC_API_ID.equalsIgnoreCase(compilerId); - final boolean isEclipse = JavaCompilers.ECLIPSE_ID.equalsIgnoreCase(compilerId) || JavaCompilers.ECLIPSE_EMBEDDED_ID.equalsIgnoreCase(compilerId); - IS_COMPILER_API_SUPPORTED.set(context, isJavac || isEclipse); - String messageText = null; - if (isJavac) { - messageText = "Using javac " + System.getProperty("java.version") + " to compile java sources"; - } - else if (isEclipse) { - messageText = "Using eclipse compiler to compile java sources"; - } + JavaCompilingTool compilingTool = JavaBuilderUtil.findCompilingTool(compilerId); + COMPILING_TOOL.set(context, compilingTool); + String messageText = compilingTool != null ? "Using " + compilingTool.getDescription() + " to compile java sources" : null; COMPILER_VERSION_INFO.set(context, new AtomicReference<String>(messageText)); } @@ -159,16 +153,17 @@ public class JavaBuilder extends ModuleLevelBuilder { @NotNull ModuleChunk chunk, @NotNull DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder, @NotNull OutputConsumer outputConsumer) throws ProjectBuildException, IOException { - if (!IS_ENABLED.get(context, Boolean.TRUE) || !IS_COMPILER_API_SUPPORTED.get(context, Boolean.TRUE)) { + JavaCompilingTool compilingTool = COMPILING_TOOL.get(context); + if (!IS_ENABLED.get(context, Boolean.TRUE) || compilingTool == null) { return ExitCode.NOTHING_DONE; } - return doBuild(context, chunk, dirtyFilesHolder, outputConsumer); + return doBuild(context, chunk, dirtyFilesHolder, outputConsumer, compilingTool); } public ExitCode doBuild(@NotNull CompileContext context, @NotNull ModuleChunk chunk, @NotNull DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder, - @NotNull OutputConsumer outputConsumer) throws ProjectBuildException, IOException { + @NotNull OutputConsumer outputConsumer, JavaCompilingTool compilingTool) throws ProjectBuildException, IOException { try { final Set<File> filesToCompile = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY); @@ -190,7 +185,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - return compile(context, chunk, dirtyFilesHolder, filesToCompile, outputConsumer); + return compile(context, chunk, dirtyFilesHolder, filesToCompile, outputConsumer, compilingTool); } catch (BuildDataCorruptedException e) { throw e; @@ -224,7 +219,7 @@ public class JavaBuilder extends ModuleLevelBuilder { ModuleChunk chunk, DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder, Collection<File> files, - OutputConsumer outputConsumer) + OutputConsumer outputConsumer, @NotNull JavaCompilingTool compilingTool) throws Exception { ExitCode exitCode = ExitCode.NOTHING_DONE; @@ -243,7 +238,7 @@ public class JavaBuilder extends ModuleLevelBuilder { // begin compilation round final Mappings delta = pd.dataManager.getMappings().createDelta(); final Callbacks.Backend mappingsCallback = delta.getCallback(); - final OutputFilesSink outputSink = new OutputFilesSink(context, outputConsumer, mappingsCallback, chunk.getName()); + final OutputFilesSink outputSink = new OutputFilesSink(context, outputConsumer, mappingsCallback, chunk.getPresentableShortName()); try { if (hasSourcesToCompile) { final AtomicReference<String> ref = COMPILER_VERSION_INFO.get(context); @@ -264,7 +259,7 @@ public class JavaBuilder extends ModuleLevelBuilder { final DiagnosticSink diagnosticSink = new DiagnosticSink(context); final String chunkName = chunk.getName(); - context.processMessage(new ProgressMessage("Parsing java... [" + chunkName + "]")); + context.processMessage(new ProgressMessage("Parsing java... [" + chunk.getPresentableShortName() + "]")); final int filesCount = files.size(); boolean compiledOk = true; @@ -284,7 +279,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } } try { - compiledOk = compileJava(context, chunk, files, classpath, platformCp, srcPath, diagnosticSink, outputSink); + compiledOk = compileJava(context, chunk, files, classpath, platformCp, srcPath, diagnosticSink, outputSink, compilingTool); } finally { // heuristic: incorrect paths data recovery, so that the next make should not contain non-existing sources in 'recompile' list @@ -328,7 +323,7 @@ public class JavaBuilder extends ModuleLevelBuilder { Collection<File> platformCp, Collection<File> sourcePath, DiagnosticOutputConsumer diagnosticSink, - final OutputFileConsumer outputSink) throws Exception { + final OutputFileConsumer outputSink, JavaCompilingTool compilingTool) throws Exception { final TasksCounter counter = new TasksCounter(); COUNTER_KEY.set(context, counter); @@ -372,7 +367,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } final Map<File, Set<File>> outs = buildOutputDirectoriesMap(context, chunk); - final List<String> options = getCompilationOptions(context, chunk, profile); + final List<String> options = getCompilationOptions(context, chunk, profile, compilingTool); final ClassProcessingConsumer classesConsumer = new ClassProcessingConsumer(context, outputSink); if (LOG.isDebugEnabled()) { LOG.debug("Compiling chunk [" + chunk.getName() + "] with options: \"" + StringUtil.join(options, " ") + "\""); @@ -380,13 +375,11 @@ public class JavaBuilder extends ModuleLevelBuilder { try { final boolean rc; if (USE_EMBEDDED_JAVAC) { - final boolean useEclipse = useEclipseCompiler(context); - rc = JavacMain.compile( - options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus(), useEclipse - ); + rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, + context.getCancelStatus(), compilingTool); } else { - final JavacServerClient client = ensureJavacServerLaunched(context); + final JavacServerClient client = ensureJavacServerLaunched(context, compilingTool); final RequestFuture<JavacServerResponseHandler> future = client.sendCompileRequest( options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer ); @@ -404,13 +397,6 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - private static boolean useEclipseCompiler(CompileContext context) { - JpsProject project = context.getProjectDescriptor().getProject(); - final JpsJavaCompilerConfiguration configuration = JpsJavaExtensionService.getInstance().getCompilerConfiguration(project); - final String compilerId = configuration != null? configuration.getJavaCompilerId() : null; - return JavaCompilers.ECLIPSE_ID.equalsIgnoreCase(compilerId) || JavaCompilers.ECLIPSE_EMBEDDED_ID.equalsIgnoreCase(compilerId); - } - private void submitAsyncTask(final CompileContext context, final Runnable taskRunnable) { final TasksCounter counter = COUNTER_KEY.get(context); @@ -432,7 +418,7 @@ public class JavaBuilder extends ModuleLevelBuilder { }); } - private static synchronized JavacServerClient ensureJavacServerLaunched(CompileContext context) throws Exception { + private static synchronized JavacServerClient ensureJavacServerLaunched(@NotNull CompileContext context, @NotNull JavaCompilingTool compilingTool) throws Exception { final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context); if (descriptor != null) { return descriptor.client; @@ -445,7 +431,7 @@ public class JavaBuilder extends ModuleLevelBuilder { final String javaHome = SystemProperties.getJavaHome(); final BaseOSProcessHandler processHandler = JavacServerBootstrap.launchJavacServer( - javaHome, heapSize, port, Utils.getSystemRoot(), getCompilationVMOptions(context), useEclipseCompiler(context) + javaHome, heapSize, port, Utils.getSystemRoot(), getCompilationVMOptions(context, compilingTool), compilingTool ); final JavacServerClient client = new JavacServerClient(); try { @@ -529,19 +515,22 @@ public class JavaBuilder extends ModuleLevelBuilder { private static final Key<List<String>> JAVAC_VM_OPTIONS = Key.create("_javac_vm_options_"); private static final Key<String> USER_DEFINED_BYTECODE_TARGET = Key.create("_user_defined_bytecode_target_"); - private static List<String> getCompilationVMOptions(CompileContext context) { + private static List<String> getCompilationVMOptions(CompileContext context, JavaCompilingTool compilingTool) { List<String> cached = JAVAC_VM_OPTIONS.get(context); if (cached == null) { - loadCommonJavacOptions(context); + loadCommonJavacOptions(context, compilingTool); cached = JAVAC_VM_OPTIONS.get(context); } return cached; } - private static List<String> getCompilationOptions(CompileContext context, ModuleChunk chunk, @Nullable ProcessorConfigProfile profile) { + private static List<String> getCompilationOptions(CompileContext context, + ModuleChunk chunk, + @Nullable ProcessorConfigProfile profile, + @NotNull JavaCompilingTool compilingTool) { List<String> cached = JAVAC_OPTIONS.get(context); if (cached == null) { - loadCommonJavacOptions(context); + loadCommonJavacOptions(context, compilingTool); cached = JAVAC_OPTIONS.get(context); assert cached != null : context; } @@ -701,7 +690,7 @@ public class JavaBuilder extends ModuleLevelBuilder { return javaVersion; } - private static void loadCommonJavacOptions(CompileContext context) { + private static void loadCommonJavacOptions(@NotNull CompileContext context, @NotNull JavaCompilingTool compilingTool) { final List<String> options = new ArrayList<String>(); final List<String> vmOptions = new ArrayList<String>(); @@ -755,14 +744,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - if (useEclipseCompiler(context)) { - for (String option : options) { - if (option.startsWith("-proceedOnError")) { - Utils.PROCEED_ON_ERROR_KEY.set(context, Boolean.TRUE); - break; - } - } - } + compilingTool.processCompilerOptions(context, options); JAVAC_OPTIONS.set(context, options); JAVAC_VM_OPTIONS.set(context, vmOptions); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java index 9d34bbb05366..2d40d9faf1e6 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java @@ -37,19 +37,19 @@ public class CompilerMessage extends BuildMessage { private final long myLine; private final long myColumn; - public CompilerMessage(String compilerName, @NotNull Throwable internalError) { + public CompilerMessage(@NotNull String compilerName, @NotNull Throwable internalError) { this(compilerName, Kind.ERROR, getTextFromThrowable(internalError), null, -1L, -1L, -1L, -1L, -1L); } - public CompilerMessage(String compilerName, Kind kind, String messageText) { + public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText) { this(compilerName, kind, messageText, null, -1L, -1L, -1L, -1L, -1L); } - public CompilerMessage(String compilerName, Kind kind, String messageText, String sourcePath) { + public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText, String sourcePath) { this(compilerName, kind, messageText, sourcePath, -1L, -1L, -1L, -1L, -1L); } - public CompilerMessage(String compilerName, Kind kind, String messageText, + public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText, @Nullable String sourcePath, long problemBeginOffset, long problemEndOffset, @@ -66,6 +66,7 @@ public class CompilerMessage extends BuildMessage { myColumn = locationColumn; } + @NotNull public String getCompilerName() { return myCompilerName; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/FileKeyDescriptor.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/FileKeyDescriptor.java index f467dd27c929..c1c364c22b80 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/FileKeyDescriptor.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/FileKeyDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.jetbrains.jps.incremental.storage; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.IOUtil; import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -31,11 +32,11 @@ import java.io.IOException; public final class FileKeyDescriptor implements KeyDescriptor<File> { private final byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); - public void save(DataOutput out, File value) throws IOException { + public void save(@NotNull DataOutput out, File value) throws IOException { IOUtil.writeUTFFast(buffer, out, value.getPath()); } - public File read(DataInput in) throws IOException { + public File read(@NotNull DataInput in) throws IOException { return new File(IOUtil.readUTFFast(buffer, in)); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/OneToManyPathsMapping.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/OneToManyPathsMapping.java index 2c0516327584..6e8eb8787e00 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/OneToManyPathsMapping.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/OneToManyPathsMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,13 +83,13 @@ public class OneToManyPathsMapping extends AbstractStateStorage<String, Collecti private static class PathCollectionExternalizer implements DataExternalizer<Collection<String>> { private final byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); - public void save(DataOutput out, Collection<String> value) throws IOException { + public void save(@NotNull DataOutput out, Collection<String> value) throws IOException { for (String str : value) { IOUtil.writeUTFFast(myBuffer, out, str); } } - public Collection<String> read(DataInput in) throws IOException { + public Collection<String> read(@NotNull DataInput in) throws IOException { final Set<String> result = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java index 9955c6a64c83..3ebb148ebb71 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -113,7 +113,7 @@ public class TimestampStorage extends AbstractStateStorage<File, TimestampStorag } private static class StateExternalizer implements DataExternalizer<TimestampPerTarget[]> { - public void save(DataOutput out, TimestampPerTarget[] value) throws IOException { + public void save(@NotNull DataOutput out, TimestampPerTarget[] value) throws IOException { out.writeInt(value.length); for (TimestampPerTarget target : value) { out.writeInt(target.targetId); @@ -121,7 +121,7 @@ public class TimestampStorage extends AbstractStateStorage<File, TimestampStorag } } - public TimestampPerTarget[] read(DataInput in) throws IOException { + public TimestampPerTarget[] read(@NotNull DataInput in) throws IOException { int size = in.readInt(); TimestampPerTarget[] targets = new TimestampPerTarget[size]; for (int i = 0; i < size; i++) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java index d9c58323804b..450dea158675 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java @@ -16,11 +16,13 @@ package org.jetbrains.jps.javac; import com.intellij.openapi.util.SystemInfo; -import com.intellij.util.ExceptionUtil; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.api.CanceledStatus; +import org.jetbrains.jps.builders.impl.java.JavacCompilerTool; +import org.jetbrains.jps.builders.java.CannotCreateJavaCompilerException; +import org.jetbrains.jps.builders.java.JavaCompilingTool; import org.jetbrains.jps.builders.java.JavaSourceTransformer; import org.jetbrains.jps.cmdline.ClasspathBootstrap; import org.jetbrains.jps.incremental.LineOutputWriter; @@ -45,8 +47,7 @@ public class JavacMain { "-d", "-classpath", "-cp", "-bootclasspath" )); private static final Set<String> FILTERED_SINGLE_OPTIONS = new HashSet<String>(Arrays.<String>asList( - /*javac options*/ "-verbose", "-proc:only", "-implicit:class", "-implicit:none", "-Xprefer:newer", "-Xprefer:source", - /*eclipse options*/"-noExit" + /*javac options*/ "-verbose", "-proc:only", "-implicit:class", "-implicit:none", "-Xprefer:newer", "-Xprefer:source" )); public static boolean compile(Collection<String> options, @@ -57,52 +58,29 @@ public class JavacMain { Map<File, Set<File>> outputDirToRoots, final DiagnosticOutputConsumer diagnosticConsumer, final OutputFileConsumer outputSink, - CanceledStatus canceledStatus, boolean useEclipseCompiler) { - JavaCompiler compiler = null; - if (useEclipseCompiler) { - for (JavaCompiler javaCompiler : ServiceLoader.load(JavaCompiler.class)) { - compiler = javaCompiler; - break; - } - if (compiler == null) { - diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Eclipse Batch Compiler was not found in classpath")); - return false; - } - } - - final boolean nowUsingJavac; - if (compiler == null) { - compiler = ToolProvider.getSystemJavaCompiler(); - if (compiler == null) { - String message = "System Java Compiler was not found in classpath"; - // trying to obtain additional diagnostic for the case when compiler.jar is present, but there were problems with compiler class loading: - try { - Class.forName("com.sun.tools.javac.api.JavacTool", false, JavacMain.class.getClassLoader()); - } - catch (Throwable ex) { - message = message + ":\n" + ExceptionUtil.getThrowableText(ex); - } - diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, message)); - return false; - } - nowUsingJavac = true; + CanceledStatus canceledStatus, @NotNull JavaCompilingTool compilingTool) { + JavaCompiler compiler; + try { + compiler = compilingTool.createCompiler(); } - else { - nowUsingJavac = false; + catch (CannotCreateJavaCompilerException e) { + diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage())); + return false; } for (File outputDir : outputDirToRoots.keySet()) { outputDir.mkdirs(); } - + final List<JavaSourceTransformer> transformers = getSourceTransformers(); - final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, diagnosticConsumer, outputSink, canceledStatus, nowUsingJavac), transformers); + final boolean usingJavac = compilingTool instanceof JavacCompilerTool; + final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, diagnosticConsumer, outputSink, canceledStatus, usingJavac), transformers); fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.handleOption("-endorseddirs", Collections.singleton("").iterator()); // this will clear cached stuff - final Collection<String> _options = prepareOptions(options, nowUsingJavac); + final Collection<String> _options = prepareOptions(options, compilingTool); try { fileManager.setOutputDirectories(outputDirToRoots); @@ -115,7 +93,7 @@ public class JavacMain { if (!classpath.isEmpty()) { try { fileManager.setLocation(StandardLocation.CLASS_PATH, classpath); - if (!nowUsingJavac && !isOptionSet(options, "-processorpath")) { + if (!usingJavac && !isOptionSet(options, "-processorpath")) { // for non-javac file manager ensure annotation processor path defaults to classpath fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpath); } @@ -148,7 +126,7 @@ public class JavacMain { //noinspection IOResourceOpenedButNotSafelyClosed final LineOutputWriter out = new LineOutputWriter() { protected void lineAvailable(String line) { - if (nowUsingJavac) { + if (usingJavac) { diagnosticConsumer.outputLineAvailable(line); } else { @@ -169,6 +147,7 @@ public class JavacMain { final JavaCompiler.CompilationTask task = compiler.getTask( out, fileManager, diagnosticConsumer, _options, null, fileManager.getJavaFileObjectsFromFiles(sources) ); + compilingTool.prepareCompilationTask(task, _options); //if (!IS_VM_6_VERSION) { //todo! // // Do not add the processor for JDK 1.6 because of the bugs in javac @@ -186,7 +165,7 @@ public class JavacMain { } finally { fileManager.close(); - if (nowUsingJavac) { + if (usingJavac) { cleanupJavacNameTable(); } } @@ -221,14 +200,9 @@ public class JavacMain { return false; } - private static Collection<String> prepareOptions(final Collection<String> options, boolean usingJavac) { + private static Collection<String> prepareOptions(final Collection<String> options, @NotNull JavaCompilingTool compilingTool) { final List<String> result = new ArrayList<String>(); - if (usingJavac) { - result.add("-implicit:class"); // the option supported by javac only - } - else { // is Eclipse - result.add("-noExit"); - } + result.addAll(compilingTool.getDefaultCompilerOptions()); boolean skip = false; for (String option : options) { if (FILTERED_OPTIONS.contains(option)) { @@ -236,7 +210,7 @@ public class JavacMain { continue; } if (!skip) { - if (!FILTERED_SINGLE_OPTIONS.contains(option)) { + if (!FILTERED_SINGLE_OPTIONS.contains(option) && !compilingTool.getDefaultCompilerOptions().contains(option)) { result.add(option); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java index b5dc9bad44fb..65c92e2ae76f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java @@ -29,6 +29,9 @@ import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; import io.netty.util.concurrent.ImmediateEventExecutor; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.api.CanceledStatus; +import org.jetbrains.jps.builders.impl.java.JavacCompilerTool; +import org.jetbrains.jps.builders.java.JavaBuilderUtil; +import org.jetbrains.jps.builders.java.JavaCompilingTool; import org.jetbrains.jps.service.SharedThreadPool; import javax.tools.*; @@ -44,7 +47,7 @@ public class JavacServer { public static final int DEFAULT_SERVER_PORT = 7878; public static final String SERVER_SUCCESS_START_MESSAGE = "Javac server started successfully. Listening on port: "; public static final String SERVER_ERROR_START_MESSAGE = "Error starting Javac Server: "; - public static final String USE_ECLIPSE_COMPILER_PROPERTY = "use.eclipse.compiler"; + public static final String JPS_JAVA_COMPILING_TOOL_PROPERTY = "jps.java.compiling.tool"; private ChannelRegistrar myChannelRegistrar; @@ -153,7 +156,8 @@ public class JavacServer { }; try { - final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus, System.getProperty(USE_ECLIPSE_COMPILER_PROPERTY) != null); + JavaCompilingTool tool = getCompilingTool(); + final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus, tool); return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createBuildCompletedResponse(rc)); } catch (Throwable e) { @@ -163,6 +167,17 @@ public class JavacServer { } } + private static JavaCompilingTool getCompilingTool() { + String property = System.getProperty(JPS_JAVA_COMPILING_TOOL_PROPERTY); + if (property != null) { + JavaCompilingTool tool = JavaBuilderUtil.findCompilingTool(property); + if (tool != null) { + return tool; + } + } + return new JavacCompilerTool(); + } + private final Set<CancelHandler> myCancelHandlers = Collections.synchronizedSet(new HashSet<CancelHandler>()); public void cancelBuilds() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java index 40b646e9a8dc..bb66e9c6b09f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.concurrency.Semaphore; +import org.jetbrains.jps.builders.java.JavaCompilingTool; import org.jetbrains.jps.cmdline.ClasspathBootstrap; import org.jetbrains.jps.service.SharedThreadPool; @@ -44,7 +45,7 @@ public class JavacServerBootstrap { int port, File workingDir, List<String> vmOptions, - boolean useEclipseCompiler) throws Exception { + JavaCompilingTool compilingTool) throws Exception { final List<String> cmdLine = new ArrayList<String>(); appendParam(cmdLine, getVMExecutablePath(sdkHomePath)); appendParam(cmdLine, "-XX:MaxPermSize=150m"); @@ -82,9 +83,7 @@ public class JavacServerBootstrap { appendParam(cmdLine, "-Duser.region=" + region); } - if (useEclipseCompiler) { - appendParam(cmdLine, "-D" + JavacServer.USE_ECLIPSE_COMPILER_PROPERTY); - } + appendParam(cmdLine, "-D" + JavacServer.JPS_JAVA_COMPILING_TOOL_PROPERTY + "=" + compilingTool.getId()); // this will disable standard extensions to ensure javac is loaded from the right tools.jar appendParam(cmdLine, "-Djava.ext.dirs="); @@ -95,7 +94,7 @@ public class JavacServerBootstrap { appendParam(cmdLine, "-classpath"); - final List<File> cp = ClasspathBootstrap.getJavacServerClasspath(sdkHomePath, useEclipseCompiler); + final List<File> cp = ClasspathBootstrap.getJavacServerClasspath(sdkHomePath, compilingTool); final StringBuilder classpath = new StringBuilder(); for (File file : cp) { if (classpath.length() > 0) { @@ -156,17 +155,15 @@ public class JavacServerBootstrap { public void onTextAvailable(ProcessEvent event, Key outputType) { if (outputType == ProcessOutputTypes.STDERR) { - try { - final String text = event.getText(); - if (text != null) { - if (text.contains(JavacServer.SERVER_SUCCESS_START_MESSAGE) || text.contains(JavacServer.SERVER_ERROR_START_MESSAGE)) { - processHandler.removeProcessListener(this); - serverStartMessage.set(text); - } + final String text = event.getText(); + if (text != null && (text.contains(JavacServer.SERVER_SUCCESS_START_MESSAGE) || text.contains(JavacServer.SERVER_ERROR_START_MESSAGE))) { + try { + processHandler.removeProcessListener(this); + serverStartMessage.set(text); + } + finally { + semaphore.up(); } - } - finally { - semaphore.up(); } } } diff --git a/jps/model-impl/jps-model-impl.iml b/jps/model-impl/jps-model-impl.iml index 5e72944c0f30..447c25cc7583 100644 --- a/jps/model-impl/jps-model-impl.iml +++ b/jps/model-impl/jps-model-impl.iml @@ -4,13 +4,11 @@ <exclude-output /> <content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" /> </content> <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="module" module-name="util" /> <orderEntry type="module" module-name="jps-model-api" /> - <orderEntry type="module" module-name="testFramework" scope="TEST" /> </component> </module> diff --git a/jps/model-impl/jps-model-tests.iml b/jps/model-impl/jps-model-tests.iml new file mode 100644 index 000000000000..f42308922277 --- /dev/null +++ b/jps/model-impl/jps-model-tests.iml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$/testSrc"> + <sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module" module-name="jps-model-impl" /> + <orderEntry type="module" module-name="testFramework" exported="" scope="TEST" /> + </component> +</module> + diff --git a/jps/model-serialization/jps-model-serialization.iml b/jps/model-serialization/jps-model-serialization.iml index 988e3c506729..6859151b1bd5 100644 --- a/jps/model-serialization/jps-model-serialization.iml +++ b/jps/model-serialization/jps-model-serialization.iml @@ -4,15 +4,12 @@ <exclude-output /> <content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" /> </content> <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="module" module-name="util" /> <orderEntry type="module" module-name="jps-model-api" /> <orderEntry type="library" exported="" name="JDOM" level="project" /> - <orderEntry type="module" module-name="jps-model-impl" exported="" scope="TEST" /> - <orderEntry type="module" module-name="testFramework" exported="" scope="TEST" /> </component> </module> diff --git a/jps/model-serialization/jps-serialization-tests.iml b/jps/model-serialization/jps-serialization-tests.iml new file mode 100644 index 000000000000..953fef28dd82 --- /dev/null +++ b/jps/model-serialization/jps-serialization-tests.iml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$/testSrc"> + <sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module" module-name="jps-model-serialization" /> + <orderEntry type="module" module-name="jps-model-tests" exported="" scope="TEST" /> + </component> +</module> + diff --git a/lib/netty-all-5.0.0.Alpha1.jar b/lib/netty-all-5.0.0.Alpha2.jar Binary files differindex ff0afa01af44..d4b646a22a83 100644 --- a/lib/netty-all-5.0.0.Alpha1.jar +++ b/lib/netty-all-5.0.0.Alpha2.jar diff --git a/lib/required_for_dist.txt b/lib/required_for_dist.txt index 2e7c8bfb3469..c368b9076142 100644 --- a/lib/required_for_dist.txt +++ b/lib/required_for_dist.txt @@ -40,7 +40,7 @@ microba.jar miglayout-swing.jar nanoxml-2.2.3.jar nekohtml-1.9.14.jar -netty-all-5.0.0.Alpha1.jar +netty-all-5.0.0.Alpha2.jar oromatcher.jar picocontainer.jar protobuf-2.5.0.jar diff --git a/lib/src/netty-all-5.0.0.Alpha1-sources.jar b/lib/src/netty-all-5.0.0.Alpha2-sources.jar Binary files differindex 767b4fb269df..354781d9601a 100644 --- a/lib/src/netty-all-5.0.0.Alpha1-sources.jar +++ b/lib/src/netty-all-5.0.0.Alpha2-sources.jar diff --git a/native/runner/runnerw/runnerw.vcxproj b/native/runner/runnerw/runnerw.vcxproj index c346390e3454..be49c0de94ec 100644 --- a/native/runner/runnerw/runnerw.vcxproj +++ b/native/runner/runnerw/runnerw.vcxproj @@ -23,7 +23,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v120</PlatformToolset> + <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> diff --git a/platform/bootstrap/src/com/intellij/idea/Main.java b/platform/bootstrap/src/com/intellij/idea/Main.java index 5891ad6b3abb..05cbe635cf7d 100755 --- a/platform/bootstrap/src/com/intellij/idea/Main.java +++ b/platform/bootstrap/src/com/intellij/idea/Main.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. @@ -135,25 +135,26 @@ public class Main { String platform = System.getProperty(PLATFORM_PREFIX_PROPERTY, "idea"); String patchFileName = ("jetbrains.patch.jar." + platform).toLowerCase(); String tempDir = System.getProperty("java.io.tmpdir"); - File originalPatchFile = new File(tempDir, patchFileName); - File copyPatchFile = new File(tempDir, patchFileName + "_copy"); // always delete previous patch copy - if (!FileUtilRt.delete(copyPatchFile)) { - throw new IOException("Cannot create temporary patch file"); + File patchCopy = new File(tempDir, patchFileName + "_copy"); + File log4jCopy = new File(tempDir, "log4j.jar." + platform + "_copy"); + if (!FileUtilRt.delete(patchCopy) || !FileUtilRt.delete(log4jCopy)) { + appendLog("Cannot delete temporary files in " + tempDir); + throw new IOException("Cannot delete temporary files in " + tempDir); } - appendLog("[Patch] Original patch %s: %s\n", originalPatchFile.exists() ? "exists" : "does not exist", - originalPatchFile.getAbsolutePath()); - - if (!originalPatchFile.exists()) { - return; - } - - if (!originalPatchFile.renameTo(copyPatchFile) || !FileUtilRt.delete(originalPatchFile)) { - appendLog("[Patch] Cannot create temporary patch file\n"); - throw new IOException("Cannot create temporary patch file"); + File patch = new File(tempDir, patchFileName); + appendLog("[Patch] Original patch %s: %s\n", patch.exists() ? "exists" : "does not exist", + patch.getAbsolutePath()); + if (!patch.exists()) return; + File log4j = new File(PathManager.getLibPath(), "log4j.jar"); + if (!log4j.exists()) { + appendLog("Log4J missing: " + log4j); + throw new IOException("Log4J missing: " + log4j); } + copyFile(patch, patchCopy, true); + copyFile(log4j, log4jCopy, false); int status = 0; if (Restarter.isSupported()) { @@ -168,13 +169,13 @@ public class Main { System.getProperty("java.home") + "/bin/java".replace('/', File.separatorChar), "-Xmx500m", "-classpath", - copyPatchFile.getPath() + File.pathSeparator + - PathManager.getLibPath() + File.separator + "log4j.jar", + patchCopy.getPath() + File.pathSeparator + log4jCopy.getPath(), "-Djava.io.tmpdir=" + tempDir, + "-Didea.updater.log=" + PathManager.getLogPath(), + "-Dswing.defaultlaf=" + UIManager.getSystemLookAndFeelClassName(), "com.intellij.updater.Runner", "install", - PathManager.getHomePath(), - PathManager.getLogPath()); + PathManager.getHomePath()); appendLog("[Patch] Restarted cmd: %s\n", args.toString()); @@ -191,6 +192,20 @@ public class Main { exit(status); } + private static void copyFile(File original, File copy, boolean move) throws IOException { + if (move) { + if (!original.renameTo(copy) || !FileUtilRt.delete(original)) { + throw new IOException("Cannot create temporary file: " + copy); + } + } + else { + FileUtilRt.copy(original, copy); + if (!copy.exists()) { + throw new IOException("Cannot create temporary file: " + copy); + } + } + } + public static void showMessage(String title, Throwable t) { StringWriter message = new StringWriter(); message.append("Internal error. Please report to http://"); diff --git a/platform/core-api/src/com/intellij/openapi/editor/colors/CodeInsightColors.java b/platform/core-api/src/com/intellij/openapi/editor/colors/CodeInsightColors.java index d823f67b2a16..ede02461408d 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/colors/CodeInsightColors.java +++ b/platform/core-api/src/com/intellij/openapi/editor/colors/CodeInsightColors.java @@ -32,13 +32,13 @@ public interface CodeInsightColors { TextAttributesKey DEPRECATED_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("DEPRECATED_ATTRIBUTES"); TextAttributesKey LOCAL_VARIABLE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("LOCAL_VARIABLE_ATTRIBUTES"); - TextAttributesKey REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES"); - TextAttributesKey REASSIGNED_PARAMETER_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("REASSIGNED_PARAMETER_ATTRIBUTES"); + TextAttributesKey PARAMETER_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("PARAMETER_ATTRIBUTES"); + TextAttributesKey REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES", LOCAL_VARIABLE_ATTRIBUTES); + TextAttributesKey REASSIGNED_PARAMETER_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("REASSIGNED_PARAMETER_ATTRIBUTES", PARAMETER_ATTRIBUTES); TextAttributesKey IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES"); TextAttributesKey INSTANCE_FIELD_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("INSTANCE_FIELD_ATTRIBUTES"); TextAttributesKey STATIC_FIELD_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("STATIC_FIELD_ATTRIBUTES"); TextAttributesKey STATIC_FINAL_FIELD_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("STATIC_FINAL_FIELD_ATTRIBUTES", STATIC_FIELD_ATTRIBUTES); - TextAttributesKey PARAMETER_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("PARAMETER_ATTRIBUTES"); TextAttributesKey CLASS_NAME_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("CLASS_NAME_ATTRIBUTES"); TextAttributesKey ANONYMOUS_CLASS_NAME_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("ANONYMOUS_CLASS_NAME_ATTRIBUTES"); TextAttributesKey TYPE_PARAMETER_NAME_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("TYPE_PARAMETER_NAME_ATTRIBUTES"); diff --git a/platform/core-api/src/com/intellij/openapi/fileTypes/LanguageFileType.java b/platform/core-api/src/com/intellij/openapi/fileTypes/LanguageFileType.java index fa04c3c97062..6385e73f209e 100644 --- a/platform/core-api/src/com/intellij/openapi/fileTypes/LanguageFileType.java +++ b/platform/core-api/src/com/intellij/openapi/fileTypes/LanguageFileType.java @@ -62,6 +62,10 @@ public abstract class LanguageFileType implements FileType{ return null; } + /** + * @deprecated implement own {@link com.intellij.debugger.engine.JVMDebugProvider} instead + */ + @Deprecated public boolean isJVMDebuggingSupported() { return false; } diff --git a/platform/core-api/src/com/intellij/openapi/module/Module.java b/platform/core-api/src/com/intellij/openapi/module/Module.java index b4218975311a..6120cb0d49d3 100644 --- a/platform/core-api/src/com/intellij/openapi/module/Module.java +++ b/platform/core-api/src/com/intellij/openapi/module/Module.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. @@ -107,8 +107,10 @@ public interface Module extends ComponentManager, AreaInstance, Disposable { * * @return scope including sources and tests, excluding libraries and dependencies. */ + @NotNull GlobalSearchScope getModuleScope(); + @NotNull GlobalSearchScope getModuleScope(boolean includeTests); /** @@ -116,6 +118,7 @@ public interface Module extends ComponentManager, AreaInstance, Disposable { * * @return scope including sources, tests, and libraries, excluding dependencies. */ + @NotNull GlobalSearchScope getModuleWithLibrariesScope(); /** @@ -123,13 +126,20 @@ public interface Module extends ComponentManager, AreaInstance, Disposable { * * @return scope including sources, tests, and dependencies, excluding libraries. */ + @NotNull GlobalSearchScope getModuleWithDependenciesScope(); + @NotNull GlobalSearchScope getModuleContentScope(); + @NotNull GlobalSearchScope getModuleContentWithDependenciesScope(); + @NotNull GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(boolean includeTests); + @NotNull GlobalSearchScope getModuleWithDependentsScope(); + @NotNull GlobalSearchScope getModuleTestsWithDependentsScope(); + @NotNull GlobalSearchScope getModuleRuntimeScope(boolean includeTests); } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java index 8b67321dc6c8..e1c23aa071d8 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.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. @@ -125,6 +125,7 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica * @return the path */ @SuppressWarnings("JavadocReference") + @NotNull public abstract String getPath(); /** @@ -727,4 +728,18 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica public static boolean isValidName(@NotNull String name) { return name.indexOf('\\') < 0 && name.indexOf('/') < 0; } + + private static final Key<String> DETECTED_LINE_SEPARATOR_KEY = Key.create("DETECTED_LINE_SEPARATOR_KEY"); + + /** + * @return Line separator for this file. + * It is always null for directories and binaries, and possibly null if a separator isn't yet known. + * @see com.intellij.util.LineSeparator + */ + public String getDetectedLineSeparator() { + return getUserData(DETECTED_LINE_SEPARATOR_KEY); + } + public void setDetectedLineSeparator(@Nullable String separator) { + putUserData(DETECTED_LINE_SEPARATOR_KEY, separator); + } } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/encoding/EncodingRegistry.java b/platform/core-api/src/com/intellij/openapi/vfs/encoding/EncodingRegistry.java index 34907f8384c1..5a9a904e5758 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/encoding/EncodingRegistry.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/encoding/EncodingRegistry.java @@ -53,6 +53,11 @@ public abstract class EncodingRegistry { public abstract void setEncoding(@Nullable("null means project") VirtualFile virtualFileOrDir, @Nullable("null means remove mapping") Charset charset); + @Nullable("null means 'use system-default'") + public Charset getDefaultCharsetForPropertiesFiles(@Nullable VirtualFile virtualFile) { + return null; + } + public static EncodingRegistry getInstance() { if (ourInstanceGetter == null) { return (EncodingRegistry)ApplicationManager.getApplication().getPicoContainer().getComponentInstance("com.intellij.openapi.vfs.encoding.EncodingManager"); diff --git a/platform/core-api/src/com/intellij/psi/CommonClassNames.java b/platform/core-api/src/com/intellij/psi/CommonClassNames.java index a7b6649666b4..32485e7a9066 100644 --- a/platform/core-api/src/com/intellij/psi/CommonClassNames.java +++ b/platform/core-api/src/com/intellij/psi/CommonClassNames.java @@ -61,6 +61,7 @@ public interface CommonClassNames { @NonNls String JAVA_UTIL_LIST = "java.util.List"; @NonNls String JAVA_UTIL_ARRAY_LIST = "java.util.ArrayList"; @NonNls String JAVA_UTIL_SET = "java.util.Set"; + @NonNls String JAVA_UTIL_HASH_SET = "java.util.HashSet"; @NonNls String JAVA_UTIL_PROPERTIES = "java.util.Properties"; @NonNls String JAVA_UTIL_PROPERTY_RESOURCE_BUNDLE = "java.util.PropertyResourceBundle"; @NonNls String JAVA_UTIL_DATE = "java.util.Date"; diff --git a/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java b/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java index a94a146ba83a..836ad0c5a924 100644 --- a/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java +++ b/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java @@ -39,7 +39,7 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw private static final Logger LOG = Logger.getInstance("#com.intellij.psi.search.GlobalSearchScope"); @Nullable private final Project myProject; - protected GlobalSearchScope(Project project) { + protected GlobalSearchScope(@Nullable Project project) { myProject = project; } @@ -49,6 +49,7 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw public abstract boolean contains(@NotNull VirtualFile file); + @Nullable @Override public Project getProject() { return myProject; diff --git a/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java b/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java index d33ee461f1cb..bb6273bb5a7c 100644 --- a/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java +++ b/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java @@ -520,17 +520,27 @@ public class PsiTreeUtil { @Nullable @Contract("null, _, _ -> null") public static <T extends PsiElement> T getParentOfType(@Nullable PsiElement element, @NotNull Class<T> aClass, boolean strict) { - if (element == null) return null; + return getParentOfType(element, aClass, strict, -1); + } + + @Contract("null, _, _, _ -> null") + public static <T extends PsiElement> T getParentOfType(@Nullable PsiElement element, @NotNull Class<T> aClass, boolean strict, int minStartOffset) { + if (element == null) { + return null; + } + if (strict) { element = element.getParent(); } - while (element != null) { + while (element != null && (minStartOffset == -1 || element.getNode().getStartOffset() >= minStartOffset)) { if (aClass.isInstance(element)) { //noinspection unchecked return (T)element; } - if (element instanceof PsiFile) return null; + if (element instanceof PsiFile) { + return null; + } element = element.getParent(); } diff --git a/platform/core-api/src/com/intellij/testFramework/LightVirtualFile.java b/platform/core-api/src/com/intellij/testFramework/LightVirtualFile.java index 158144a369b1..55222cff9448 100644 --- a/platform/core-api/src/com/intellij/testFramework/LightVirtualFile.java +++ b/platform/core-api/src/com/intellij/testFramework/LightVirtualFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -184,6 +184,7 @@ public class LightVirtualFile extends VirtualFile { return myFileType; } + @NotNull @Override public String getPath() { return "/" + getName(); diff --git a/platform/core-api/src/com/intellij/util/PlatformUtilsCore.java b/platform/core-api/src/com/intellij/util/PlatformUtilsCore.java index 19854ccdb88e..5172e155cd14 100644 --- a/platform/core-api/src/com/intellij/util/PlatformUtilsCore.java +++ b/platform/core-api/src/com/intellij/util/PlatformUtilsCore.java @@ -24,7 +24,7 @@ public class PlatformUtilsCore { public static final String APPCODE_PREFIX = "AppCode"; public static final String CPP_PREFIX = "CppIde"; public static final String PYCHARM_PREFIX = "Python"; - public static final String PYCHARM_PREFIX2 = "PyCharm"; + public static final String PYCHARM_PREFIX2 = "PyCharmCore"; public static final String RUBY_PREFIX = "Ruby"; public static final String PHP_PREFIX = "PhpStorm"; public static final String WEB_PREFIX = "WebStorm"; diff --git a/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArray.java b/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArray.java index b3e91d67ad05..2918656a952b 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArray.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArray.java @@ -27,8 +27,8 @@ import org.jetbrains.annotations.NotNull; */ public class SegmentArray { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.ex.util.SegmentArray"); - private int[] myStarts; - private int[] myEnds; + protected int[] myStarts; + protected int[] myEnds; protected int mySegmentCount = 0; protected static final int INITIAL_SIZE = 64; @@ -84,26 +84,32 @@ public class SegmentArray { return newArray; } + protected int noSegmentsAvailable(int offset) { + throw new IllegalStateException("no segments available. offset = " + offset); + } + + protected int offsetOutOfRange(int offset, int lastValidOffset) { + throw new IndexOutOfBoundsException("Wrong offset: " + offset + ". Should be in range: [0, " + lastValidOffset + "]"); + } + public final int findSegmentIndex(int offset) { if (mySegmentCount <= 0) { - if (offset == 0) return 0; - throw new IllegalStateException("no segments available. offset = "+offset); + return offset == 0 ? 0 : noSegmentsAvailable(offset); } final int lastValidOffset = getLastValidOffset(); - if (offset > lastValidOffset || offset < 0) { - throw new IndexOutOfBoundsException("Wrong offset: " + offset + ". Should be in range: [0, " + lastValidOffset + "]"); + return offsetOutOfRange(offset, lastValidOffset); } - final int lastValidIndex = mySegmentCount - 1; - if (offset == lastValidOffset) return lastValidIndex; + int end = mySegmentCount - 1; + if (offset == lastValidOffset) { + return end; + } int start = 0; - int end = lastValidIndex; - - while (start < end) { - int i = (start + end) / 2; + while (start <= end) { + int i = (start + end) >>> 1; if (offset < myStarts[i]) { end = i - 1; } @@ -115,9 +121,12 @@ public class SegmentArray { } } + return segmentNotFound(offset, start); + } + + protected int segmentNotFound(int offset, int start) { // This means that there is a gap at given offset assert myStarts[start] <= offset && offset < myEnds[start] : start; - return start; } 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 3d51b6ba470c..6be740bc6364 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 @@ -59,7 +59,8 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { private final List<RangeMarker> myGuardedBlocks = new ArrayList<RangeMarker>(); private ReadonlyFragmentModificationHandler myReadonlyFragmentModificationHandler; - private final LineSet myLineSet = new LineSet(); + private final Object myLineSetLock = new String("line set lock"); + private volatile LineSet myLineSet; private volatile ImmutableText myText; private volatile SoftReference<String> myTextString; @@ -110,9 +111,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { } public DocumentImpl(@NotNull CharSequence chars, boolean forUseInNonAWTThread) { + this(chars, false, forUseInNonAWTThread); + } + + public DocumentImpl(@NotNull CharSequence chars, boolean acceptSlashR, boolean forUseInNonAWTThread) { + setAcceptSlashR(acceptSlashR); assertValidSeparators(chars); myText = ImmutableText.valueOf(chars); - myLineSet.documentCreated(this); setCyclicBufferSize(0); setModificationStamp(LocalTimeCounter.currentTime()); myAssertThreading = !forUseInNonAWTThread; @@ -127,6 +132,22 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { } } + private LineSet getLineSet() { + LineSet lineSet = myLineSet; + if (lineSet == null) { + synchronized (myLineSetLock) { + lineSet = myLineSet; + if (lineSet == null) { + lineSet = new LineSet(); + lineSet.documentCreated(this); + myLineSet = lineSet; + } + } + } + + return lineSet; + } + @Override @NotNull public char[] getChars() { @@ -159,11 +180,12 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { CharSequence text = myText; RangeMarker caretMarker = caretOffset < 0 || caretOffset > getTextLength() ? null : createRangeMarker(caretOffset, caretOffset); try { - for (int line = 0; line < myLineSet.getLineCount(); line++) { - if (inChangedLinesOnly && !myLineSet.isModified(line)) continue; + LineSet lineSet = getLineSet(); + for (int line = 0; line < lineSet.getLineCount(); line++) { + if (inChangedLinesOnly && !lineSet.isModified(line)) continue; int whiteSpaceStart = -1; - final int lineEnd = myLineSet.getLineEnd(line) - myLineSet.getSeparatorLength(line); - int lineStart = myLineSet.getLineStart(line); + final int lineEnd = lineSet.getLineEnd(line) - lineSet.getSeparatorLength(line); + int lineStart = lineSet.getLineStart(line); for (int offset = lineEnd - 1; offset >= lineStart; offset--) { char c = text.charAt(offset); if (c != ' ' && c != '\t') { @@ -228,12 +250,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { markers.add(marker); } } + LineSet lineSet = getLineSet(); lineLoop: - for (int line = 0; line < myLineSet.getLineCount(); line++) { - if (inChangedLinesOnly && !myLineSet.isModified(line)) continue; + for (int line = 0; line < lineSet.getLineCount(); line++) { + if (inChangedLinesOnly && !lineSet.isModified(line)) continue; int whiteSpaceStart = -1; - final int lineEnd = myLineSet.getLineEnd(line) - myLineSet.getSeparatorLength(line); - int lineStart = myLineSet.getLineStart(line); + final int lineEnd = lineSet.getLineEnd(line) - lineSet.getSeparatorLength(line); + int lineStart = lineSet.getLineStart(line); for (int offset = lineEnd - 1; offset >= lineStart; offset--) { char c = text.charAt(offset); if (c != ' ' && c != '\t') { @@ -644,19 +667,20 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { @Override public void clearLineModificationFlags() { - myLineSet.clearModificationFlags(); + getLineSet().clearModificationFlags(); } public void clearLineModificationFlagsExcept(@NotNull List<Integer> caretLines) { List<Integer> modifiedLines = new ArrayList<Integer>(caretLines.size()); + LineSet lineSet = getLineSet(); for (Integer line : caretLines) { - if (line != null && line >= 0 && line < myLineSet.getLineCount() && myLineSet.isModified(line)) { + if (line != null && line >= 0 && line < lineSet.getLineCount() && lineSet.isModified(line)) { modifiedLines.add(line); } } clearLineModificationFlags(); for (Integer line : modifiedLines) { - myLineSet.setModified(line); + lineSet.setModified(line); } } @@ -694,6 +718,8 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { } assertInsideCommand(); + getLineSet(); // initialize line set to track changed lines + DocumentEvent event = new DocumentEventImpl(this, offset, oldString, newString, myModificationStamp, wholeTextReplaced); if (!ShutDownTracker.isShutdownHookRunning()) { @@ -725,7 +751,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { try { if (LOG.isDebugEnabled()) LOG.debug(event.toString()); - myLineSet.changedUpdate(event); + getLineSet().changedUpdate(event); setModificationStamp(newModificationStamp); if (!ShutDownTracker.isShutdownHookRunning()) { @@ -847,39 +873,39 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { @Override public int getLineNumber(final int offset) { - return myLineSet.findLineIndex(offset); + return getLineSet().findLineIndex(offset); } @Override @NotNull public LineIterator createLineIterator() { - return myLineSet.createIterator(); + return getLineSet().createIterator(); } @Override public final int getLineStartOffset(final int line) { if (line == 0) return 0; // otherwise it crashed for zero-length document - return myLineSet.getLineStart(line); + return getLineSet().getLineStart(line); } @Override public final int getLineEndOffset(int line) { if (getTextLength() == 0 && line == 0) return 0; - int result = myLineSet.getLineEnd(line) - getLineSeparatorLength(line); + int result = getLineSet().getLineEnd(line) - getLineSeparatorLength(line); assert result >= 0; return result; } @Override public final int getLineSeparatorLength(int line) { - int separatorLength = myLineSet.getSeparatorLength(line); + int separatorLength = getLineSet().getSeparatorLength(line); assert separatorLength >= 0; return separatorLength; } @Override public final int getLineCount() { - int lineCount = myLineSet.getLineCount(); + int lineCount = getLineSet().getLineCount(); assert lineCount >= 0; return lineCount; } diff --git a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java index d621140f132b..a0baadbb8096 100644 --- a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.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. @@ -40,7 +40,6 @@ import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; public final class LoadTextUtil { - private static final Key<String> DETECTED_LINE_SEPARATOR_KEY = Key.create("DETECTED_LINE_SEPARATOR_KEY"); @Nls private static final String AUTO_DETECTED_FROM_BOM = "auto-detected from BOM"; private LoadTextUtil() { @@ -215,7 +214,7 @@ public final class LoadTextUtil { } String newText = StringUtil.convertLineSeparators(currentText.toString(), newSeparator); - file.putUserData(DETECTED_LINE_SEPARATOR_KEY, newSeparator); + file.setDetectedLineSeparator(newSeparator); write(project, file, requestor, newText, -1); } @@ -346,13 +345,7 @@ public final class LoadTextUtil { @NotNull public static CharSequence loadText(@NotNull VirtualFile file) { if (file instanceof LightVirtualFile) { - CharSequence content = ((LightVirtualFile)file).getContent(); - if (StringUtil.indexOf(content, '\r') == -1) return content; - - CharBuffer buffer = CharBuffer.allocate(content.length()); - buffer.append(content); - buffer.rewind(); - return convertLineSeparators(buffer).first; + return ((LightVirtualFile)file).getContent(); } if (file.isDirectory()) { @@ -397,7 +390,7 @@ public final class LoadTextUtil { Pair<CharSequence, String> result = convertBytes(bytes, charset, offset); if (saveDetectedSeparators) { - virtualFile.putUserData(DETECTED_LINE_SEPARATOR_KEY, result.getSecond()); + virtualFile.setDetectedLineSeparator(result.getSecond()); } return result.getFirst(); } @@ -425,7 +418,7 @@ public final class LoadTextUtil { } static String getDetectedLineSeparator(@NotNull VirtualFile file) { - return file.getUserData(DETECTED_LINE_SEPARATOR_KEY); + return file.getDetectedLineSeparator(); } @NotNull diff --git a/platform/core-impl/src/com/intellij/openapi/module/impl/ModuleScopeProvider.java b/platform/core-impl/src/com/intellij/openapi/module/impl/ModuleScopeProvider.java index 720c88d60233..58906e1b17ac 100644 --- a/platform/core-impl/src/com/intellij/openapi/module/impl/ModuleScopeProvider.java +++ b/platform/core-impl/src/com/intellij/openapi/module/impl/ModuleScopeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.intellij.openapi.module.impl; import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; /** * Author: dmitrylomov @@ -27,8 +28,10 @@ public interface ModuleScopeProvider { * * @return scope including sources and tests, excluding libraries and dependencies. */ + @NotNull GlobalSearchScope getModuleScope(); + @NotNull GlobalSearchScope getModuleScope(boolean includeTests); /** @@ -36,6 +39,7 @@ public interface ModuleScopeProvider { * * @return scope including sources, tests, and libraries, excluding dependencies. */ + @NotNull GlobalSearchScope getModuleWithLibrariesScope(); /** @@ -43,14 +47,21 @@ public interface ModuleScopeProvider { * * @return scope including sources, tests, and dependencies, excluding libraries. */ + @NotNull GlobalSearchScope getModuleWithDependenciesScope(); + @NotNull GlobalSearchScope getModuleContentScope(); + @NotNull GlobalSearchScope getModuleContentWithDependenciesScope(); + @NotNull GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(boolean includeTests); + @NotNull GlobalSearchScope getModuleWithDependentsScope(); + @NotNull GlobalSearchScope getModuleTestsWithDependentsScope(); + @NotNull GlobalSearchScope getModuleRuntimeScope(boolean includeTests); void clearCache(); diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/CoreJarVirtualFile.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/CoreJarVirtualFile.java index 3827ecc2da66..1256c54f3f5d 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/CoreJarVirtualFile.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/CoreJarVirtualFile.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. @@ -18,11 +18,13 @@ package com.intellij.openapi.vfs.impl.jar; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileSystem; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.List; /** * @author yole @@ -30,10 +32,10 @@ import java.util.ArrayList; public class CoreJarVirtualFile extends VirtualFile { private final CoreJarHandler myHandler; private final VirtualFile myParent; - private final ArrayList<VirtualFile> myChildren = new ArrayList<VirtualFile>(); + private final List<VirtualFile> myChildren = new ArrayList<VirtualFile>(); private final JarHandlerBase.EntryInfo myEntry; - public CoreJarVirtualFile(CoreJarHandler handler, JarHandlerBase.EntryInfo entry, CoreJarVirtualFile parent) { + public CoreJarVirtualFile(@NotNull CoreJarHandler handler, @NotNull JarHandlerBase.EntryInfo entry, @Nullable CoreJarVirtualFile parent) { myHandler = handler; myParent = parent; myEntry = entry; @@ -56,6 +58,7 @@ public class CoreJarVirtualFile extends VirtualFile { } @Override + @NotNull public String getPath() { if (myParent == null) return myHandler.myBasePath + "!/"; diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java index 4dba701485a1..0648e3d319e1 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.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. @@ -52,6 +52,7 @@ public class JarHandlerBase { protected static class EntryInfo { protected final boolean isDirectory; + @NotNull protected final String shortName; protected final EntryInfo parent; diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/local/CoreLocalVirtualFile.java b/platform/core-impl/src/com/intellij/openapi/vfs/local/CoreLocalVirtualFile.java index c3b770af072b..016cab9a818b 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/local/CoreLocalVirtualFile.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/local/CoreLocalVirtualFile.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. @@ -56,6 +56,7 @@ public class CoreLocalVirtualFile extends VirtualFile { return myFileSystem; } + @NotNull @Override public String getPath() { return FileUtil.toSystemIndependentName(myIoFile.getAbsolutePath()); diff --git a/platform/dvcs/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java b/platform/dvcs/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java index 56900785e57b..26c87c7de627 100644 --- a/platform/dvcs/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java +++ b/platform/dvcs/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java @@ -24,10 +24,13 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.CheckinProjectPanel; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.ui.RefreshableOnComponent; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.NonFocusableCheckBox; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,8 +39,9 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.Collection; -import java.util.LinkedHashSet; +import java.io.File; +import java.util.*; +import java.util.List; /** * @author Nadya Zabrodina @@ -51,6 +55,7 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp @Nullable private String myPreviousMessage; @Nullable private String myAmendedMessage; @NotNull protected final CheckinProjectPanel myCheckinPanel; + @Nullable private Map<VirtualFile, String> myMessagesForRoots; public DvcsCommitAdditionalComponent(@NotNull final Project project, @NotNull CheckinProjectPanel panel) { myCheckinPanel = panel; @@ -76,14 +81,16 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp @Override public void actionPerformed(ActionEvent e) { if (myAmend.isSelected()) { - if (myPreviousMessage.equals(myCheckinPanel.getCommitMessage())) { // if user has already typed something, don't revert it - if (myAmendedMessage == null) { - loadMessageInModalTask(project); + if (myPreviousMessage.equals(myCheckinPanel.getCommitMessage())) { // if user has already typed something, don't revert it + if (myMessagesForRoots == null) { + loadMessagesInModalTask(project); //load all commit messages for all repositories + } + String message = constructAmendedMessage(); + if (!StringUtil.isEmptyOrSpaces(message)) { + myAmendedMessage = message; + substituteCommitMessage(myAmendedMessage); + } } - else { // checkbox is selected not the first time - substituteCommitMessage(myAmendedMessage); - } - } } else { // there was the amended message, but user has changed it => not reverting @@ -96,6 +103,20 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp myPanel.add(myAmend, c); } + private String constructAmendedMessage() { + Set<VirtualFile> selectedRoots = getVcsRoots(getSelectedFilePaths()); // get only selected files + LinkedHashSet<String> messages = ContainerUtil.newLinkedHashSet(); + if (myMessagesForRoots != null) { + for (VirtualFile root : selectedRoots) { + String message = myMessagesForRoots.get(root); + if (message != null) { + messages.add(message); + } + } + } + return DvcsUtil.joinMessagesOrNull(messages); + } + public JComponent getComponent() { return myPanel; } @@ -104,19 +125,15 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp myAmend.setSelected(false); } - private void loadMessageInModalTask(@NotNull Project project) { + private void loadMessagesInModalTask(@NotNull Project project) { try { - String messageFromVcs = - ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable<String, VcsException>() { + myMessagesForRoots = + ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable<Map<VirtualFile,String>, VcsException>() { @Override - public String compute() throws VcsException { - return getLastCommitMessage(); + public Map<VirtualFile, String> compute() throws VcsException { + return getLastCommitMessages(); } }, "Reading commit message...", false, project); - if (!StringUtil.isEmptyOrSpaces(messageFromVcs)) { - substituteCommitMessage(messageFromVcs); - myAmendedMessage = messageFromVcs; - } } catch (VcsException e) { Messages.showErrorDialog(getComponent(), "Couldn't load commit message of the commit to amend.\n" + e.getMessage(), @@ -133,24 +150,32 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp } @Nullable - private String getLastCommitMessage() throws VcsException { - Collection<VirtualFile> roots = getRoots(); + private Map<VirtualFile, String> getLastCommitMessages() throws VcsException { + Map<VirtualFile, String> messagesForRoots = new HashMap<VirtualFile, String>(); + Collection<VirtualFile> roots = myCheckinPanel.getRoots(); //all committed vcs roots, not only selected final Ref<VcsException> exception = Ref.create(); - LinkedHashSet<String> messages = ContainerUtil.newLinkedHashSet(); for (VirtualFile root : roots) { String message = getLastCommitMessage(root); - if (message != null) { - messages.add(message); - } + messagesForRoots.put(root, message); } if (!exception.isNull()) { throw exception.get(); } - return DvcsUtil.joinMessagesOrNull(messages); + return messagesForRoots; + } + + @NotNull + private List<FilePath> getSelectedFilePaths() { + return ContainerUtil.map(myCheckinPanel.getFiles(), new Function<File, FilePath>() { + @Override + public FilePath fun(File file) { + return new FilePathImpl(file, file.isDirectory()); + } + }); } @NotNull - protected abstract Collection<VirtualFile> getRoots(); + protected abstract Set<VirtualFile> getVcsRoots(@NotNull Collection<FilePath> files); @Nullable protected abstract String getLastCommitMessage(@NotNull VirtualFile repo) throws VcsException; diff --git a/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVirtualFile.java b/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVirtualFile.java index 2b6743c09523..3b36381dcf85 100644 --- a/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVirtualFile.java +++ b/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVirtualFile.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. @@ -39,9 +39,9 @@ import java.io.OutputStream; */ public class MockVirtualFile extends VirtualFile { - private static VirtualFileSystem ourFileSystem = new MockVirtualFileSystem(); + private static final VirtualFileSystem ourFileSystem = new MockVirtualFileSystem(); - private String myPath; + private final String myPath; @NotNull static VirtualFile fromPath(@NotNull String absolutePath) { @@ -84,6 +84,7 @@ public class MockVirtualFile extends VirtualFile { return ourFileSystem; } + @NotNull @Override public String getPath() { return myPath; @@ -179,14 +180,12 @@ public class MockVirtualFile extends VirtualFile { MockVirtualFile file = (MockVirtualFile)o; - if (myPath != null ? !myPath.equals(file.myPath) : file.myPath != null) return false; - - return true; + return myPath.equals(file.myPath); } @Override public int hashCode() { - return myPath != null ? myPath.hashCode() : 0; + return myPath.hashCode(); } } diff --git a/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java b/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java index 7a6a0cf04361..1d1540910539 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java @@ -21,13 +21,14 @@ import com.intellij.openapi.project.PossiblyDumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.SmartList; import org.intellij.lang.annotations.JdkConstants; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.ArrayList; +import java.util.List; /** * Represents an entity that has a state, a presentation and can be performed. @@ -143,9 +144,10 @@ public abstract class AnAction implements PossiblyDumbAware { public final void registerCustomShortcutSet(@NotNull ShortcutSet shortcutSet, @Nullable JComponent component){ myShortcutSet = shortcutSet; if (component != null){ - @SuppressWarnings("unchecked") ArrayList<AnAction> actionList = (ArrayList<AnAction>)component.getClientProperty(ourClientProperty); + @SuppressWarnings("unchecked") + List<AnAction> actionList = (List<AnAction>)component.getClientProperty(ourClientProperty); if (actionList == null){ - actionList = new ArrayList<AnAction>(1); + actionList = new SmartList<AnAction>(); component.putClientProperty(ourClientProperty, actionList); } if (!actionList.contains(this)){ @@ -170,7 +172,8 @@ public abstract class AnAction implements PossiblyDumbAware { public final void unregisterCustomShortcutSet(JComponent component){ if (component != null){ - @SuppressWarnings("unchecked") ArrayList<AnAction> actionList = (ArrayList<AnAction>)component.getClientProperty(ourClientProperty); + @SuppressWarnings("unchecked") + List<AnAction> actionList = (List<AnAction>)component.getClientProperty(ourClientProperty); if (actionList != null){ actionList.remove(this); } diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/Caret.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/Caret.java index 3648e477da83..43b5e75e08df 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/Caret.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/Caret.java @@ -202,6 +202,8 @@ public interface Caret extends UserDataHolderEx, Disposable { * Selects target range providing information about visual boundary of selection end. * <p/> * That is the case for soft wraps-aware processing where the whole soft wraps virtual space is matched to the same offset. + * <p/> + * Also, in column mode this method allows to create selection spanning virtual space after the line end. * * @param startOffset start selection offset * @param endPosition end visual position of the text range to select (<code>null</code> argument means that @@ -214,6 +216,8 @@ public interface Caret extends UserDataHolderEx, Disposable { * Selects target range based on its visual boundaries. * <p/> * That is the case for soft wraps-aware processing where the whole soft wraps virtual space is matched to the same offset. + * <p/> + * Also, in column mode this method allows to create selection spanning virtual space after the line end. * * @param startPosition start visual position of the text range to select (<code>null</code> argument means that * no specific visual position should be used) @@ -249,8 +253,8 @@ public interface Caret extends UserDataHolderEx, Disposable { * selection will be set for the new caret. * * @param above if <code>true</code>, new caret will be created at the previous line, if <code>false</code> - on the next line - * @return newly created caret instance, or null if the caret cannot be created because it already exists at the new location or caret - * model doesn't support multiple carets. + * @return newly created caret instance, or <code>null</code> if the caret cannot be created because it already exists at the new location + * or caret model doesn't support multiple carets. */ @Nullable Caret clone(boolean above); diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java index 17ddb3f820b3..1d26b77128b3 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java @@ -17,7 +17,6 @@ package com.intellij.openapi.editor; import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.util.Segment; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -130,14 +129,14 @@ public interface CaretModel { int getOffset(); /** - * Adds a listener for receiving notifications about caret movement. + * Adds a listener for receiving notifications about caret movement and caret addition/removal * * @param listener the listener instance. */ void addCaretListener(@NotNull CaretListener listener); /** - * Removes a listener for receiving notifications about caret movement. + * Removes a listener for receiving notifications about caret movement and caret addition/removal * * @param listener the listener instance. */ @@ -182,6 +181,11 @@ public interface CaretModel { Caret getPrimaryCaret(); /** + * Returns number of carets currently existing in the document + */ + int getCaretCount(); + + /** * Returns all carets currently existing in the document, ordered by their position in the document. */ @NotNull @@ -214,14 +218,14 @@ public interface CaretModel { void removeSecondaryCarets(); /** - * Sets the number of carets, their positions and selection ranges according to the provided parameters. Null values in any of the - * collections will mean that corresponding caret's position and/or selection won't be changed. + * Sets the number of carets, their positions and selection ranges according to the provided data. Null values for caret position or + * selection boundaries will mean that corresponding caret's position and/or selection won't be changed. * <p> * If multiple carets are not supported, the behaviour is unspecified. * * @see #supportsMultipleCarets() */ - void setCaretsAndSelections(@NotNull List<LogicalPosition> caretPositions, @NotNull List<? extends Segment> selections); + void setCaretsAndSelections(@NotNull List<CaretState> caretStates); /** * Executes the given task for each existing caret. Carets are iterated in their position order. Set of carets to iterate over is diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretState.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretState.java new file mode 100644 index 000000000000..d7588f14d194 --- /dev/null +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretState.java @@ -0,0 +1,54 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor; + +import org.jetbrains.annotations.Nullable; + +public class CaretState { + private final LogicalPosition caretPosition; + private final LogicalPosition selectionStart; + private final LogicalPosition selectionEnd; + + public CaretState(@Nullable LogicalPosition position, @Nullable LogicalPosition start, @Nullable LogicalPosition end) { + caretPosition = position; + selectionStart = start; + selectionEnd = end; + } + + @Nullable + public LogicalPosition getCaretPosition(){ + return caretPosition; + } + + @Nullable + public LogicalPosition getSelectionStart() { + return selectionStart; + } + + @Nullable + public LogicalPosition getSelectionEnd() { + return selectionEnd; + } + + @Override + public String toString() { + return "CaretState{" + + "caretPosition=" + caretPosition + + ", selectionStart=" + selectionStart + + ", selectionEnd=" + selectionEnd + + '}'; + } +} diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/event/MultipleCaretListener.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/event/CaretAdapter.java index 0c225cf922a6..86b2bac7f4fd 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/event/MultipleCaretListener.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/event/CaretAdapter.java @@ -15,21 +15,16 @@ */ package com.intellij.openapi.editor.event; -/** - * In addition to caret movement event received by CaretListener instances, these listeners will also get caret creation/destroying events. - * - * @see CaretListener - * @see com.intellij.openapi.editor.CaretModel#addCaretListener(CaretListener) - * @see EditorEventMulticaster#addCaretListener(CaretListener) - */ -public interface MultipleCaretListener extends CaretListener { - /** - * Called when a new caret was added to the document. - */ - void caretAdded(CaretEvent e); +public abstract class CaretAdapter implements CaretListener { + @Override + public void caretPositionChanged(CaretEvent e) { + } + + @Override + public void caretAdded(CaretEvent e) { + } - /** - * Called when a caret was removed from the document. - */ - void caretRemoved(CaretEvent e); + @Override + public void caretRemoved(CaretEvent e) { + } } diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/event/CaretListener.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/event/CaretListener.java index d99649c97d2f..fe73fc1a4cc5 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/event/CaretListener.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/event/CaretListener.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. @@ -18,7 +18,7 @@ package com.intellij.openapi.editor.event; import java.util.EventListener; /** - * Allows to receive notifications about caret movement. + * Allows to receive notifications about caret movement, and caret additions/removal * * @see com.intellij.openapi.editor.CaretModel#addCaretListener(CaretListener) * @see EditorEventMulticaster#addCaretListener(CaretListener) @@ -30,4 +30,14 @@ public interface CaretListener extends EventListener { * @param e the event containing information about the caret movement. */ void caretPositionChanged(CaretEvent e); + + /** + * Called when a new caret was added to the document. + */ + void caretAdded(CaretEvent e); + + /** + * Called when a caret was removed from the document. + */ + void caretRemoved(CaretEvent e); } diff --git a/platform/editor-ui-ex/src/com/intellij/injected/editor/MarkupModelWindow.java b/platform/editor-ui-ex/src/com/intellij/injected/editor/MarkupModelWindow.java index b11ff743642e..9fd72279c4f2 100644 --- a/platform/editor-ui-ex/src/com/intellij/injected/editor/MarkupModelWindow.java +++ b/platform/editor-ui-ex/src/com/intellij/injected/editor/MarkupModelWindow.java @@ -110,7 +110,7 @@ public class MarkupModelWindow extends UserDataHolderBase implements MarkupModel } @Override - public RangeHighlighter addPersistentLineHighlighter(final int line, final int layer, final TextAttributes textAttributes) { + public RangeHighlighterEx addPersistentLineHighlighter(final int line, final int layer, final TextAttributes textAttributes) { int hostLine = myDocument.injectedToHostLine(line); return myHostModel.addPersistentLineHighlighter(hostLine, layer, textAttributes); } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/MarkupModelEx.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/MarkupModelEx.java index 284ef90e2007..28d8cb447d7c 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/MarkupModelEx.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/MarkupModelEx.java @@ -33,7 +33,7 @@ public interface MarkupModelEx extends MarkupModel { void dispose(); @Nullable - RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes); + RangeHighlighterEx addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes); void fireAttributesChanged(@NotNull RangeHighlighterEx segmentHighlighter, boolean renderersChanged); diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java index d9e5c4bd51bd..a3ac344e23bf 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java @@ -109,7 +109,7 @@ public class EmptyMarkupModel implements MarkupModelEx { } @Override - public RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { + public RangeHighlighterEx addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { return null; } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java index 50a9922d1bcb..5724189b0110 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java @@ -76,13 +76,13 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx @Override @Nullable - public RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { + public RangeHighlighterEx addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { if (isNotValidLine(lineNumber)) { return null; } int offset = getFirstNonSpaceCharOffset(getDocument(), lineNumber); - return addRangeHighlighter(PersistentRangeHighlighterImpl.create(this, offset, layer, HighlighterTargetArea.LINES_IN_RANGE, null, false), null); + return addRangeHighlighter(PersistentRangeHighlighterImpl.create(this, offset, layer, HighlighterTargetArea.LINES_IN_RANGE, textAttributes, false), null); } private boolean isNotValidLine(int lineNumber) { diff --git a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index dca89ac7bf8a..08eab82f0dcf 100644 --- a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.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. @@ -70,13 +70,13 @@ public class TodoIndex extends FileBasedIndexExtension<TodoIndexEntry, Integer> } @Override - public void save(final DataOutput out, final TodoIndexEntry value) throws IOException { + public void save(@NotNull final DataOutput out, final TodoIndexEntry value) throws IOException { out.writeUTF(value.pattern); out.writeBoolean(value.caseSensitive); } @Override - public TodoIndexEntry read(final DataInput in) throws IOException { + public TodoIndexEntry read(@NotNull final DataInput in) throws IOException { final String pattern = in.readUTF(); final boolean caseSensitive = in.readBoolean(); return new TodoIndexEntry(pattern, caseSensitive); @@ -106,7 +106,7 @@ public class TodoIndex extends FileBasedIndexExtension<TodoIndexEntry, Integer> private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { if (!file.isInLocalFileSystem()) { return false; // do not index TODOs in library sources } @@ -147,16 +147,19 @@ public class TodoIndex extends FileBasedIndexExtension<TodoIndexEntry, Integer> return myIndexer; } + @NotNull @Override public KeyDescriptor<TodoIndexEntry> getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public DataExternalizer<Integer> getValueExternalizer() { return myValueExternalizer; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; diff --git a/platform/icons/src/nodes/pluginJB.png b/platform/icons/src/nodes/pluginJB.png Binary files differnew file mode 100644 index 000000000000..54b036124bf0 --- /dev/null +++ b/platform/icons/src/nodes/pluginJB.png diff --git a/platform/icons/src/nodes/pluginJB@2x.png b/platform/icons/src/nodes/pluginJB@2x.png Binary files differnew file mode 100644 index 000000000000..dbaac8fe84f1 --- /dev/null +++ b/platform/icons/src/nodes/pluginJB@2x.png diff --git a/platform/icons/src/nodes/pluginJB@2x_dark.png b/platform/icons/src/nodes/pluginJB@2x_dark.png Binary files differnew file mode 100644 index 000000000000..6af31910d8c6 --- /dev/null +++ b/platform/icons/src/nodes/pluginJB@2x_dark.png diff --git a/platform/icons/src/nodes/pluginJB_dark.png b/platform/icons/src/nodes/pluginJB_dark.png Binary files differnew file mode 100644 index 000000000000..7325cf713fa9 --- /dev/null +++ b/platform/icons/src/nodes/pluginJB_dark.png diff --git a/platform/icons/src/nodes/pluginRestart.png b/platform/icons/src/nodes/pluginRestart.png Binary files differnew file mode 100644 index 000000000000..a47d933dbeb1 --- /dev/null +++ b/platform/icons/src/nodes/pluginRestart.png diff --git a/platform/icons/src/nodes/pluginRestart@2x.png b/platform/icons/src/nodes/pluginRestart@2x.png Binary files differnew file mode 100644 index 000000000000..3c9e05c8ea49 --- /dev/null +++ b/platform/icons/src/nodes/pluginRestart@2x.png diff --git a/platform/icons/src/nodes/pluginRestart@2x_dark.png b/platform/icons/src/nodes/pluginRestart@2x_dark.png Binary files differnew file mode 100644 index 000000000000..4c4439c08ad6 --- /dev/null +++ b/platform/icons/src/nodes/pluginRestart@2x_dark.png diff --git a/platform/icons/src/nodes/pluginRestart_dark.png b/platform/icons/src/nodes/pluginRestart_dark.png Binary files differnew file mode 100644 index 000000000000..c0cc12aa9e9c --- /dev/null +++ b/platform/icons/src/nodes/pluginRestart_dark.png diff --git a/platform/icons/src/nodes/pluginUpdate.png b/platform/icons/src/nodes/pluginUpdate.png Binary files differnew file mode 100644 index 000000000000..62f0a4fbfeac --- /dev/null +++ b/platform/icons/src/nodes/pluginUpdate.png diff --git a/platform/icons/src/nodes/pluginUpdate@2x.png b/platform/icons/src/nodes/pluginUpdate@2x.png Binary files differnew file mode 100644 index 000000000000..b0b65f1f314c --- /dev/null +++ b/platform/icons/src/nodes/pluginUpdate@2x.png diff --git a/platform/icons/src/nodes/pluginUpdate@2x_dark.png b/platform/icons/src/nodes/pluginUpdate@2x_dark.png Binary files differnew file mode 100644 index 000000000000..8801cf28dcd3 --- /dev/null +++ b/platform/icons/src/nodes/pluginUpdate@2x_dark.png diff --git a/platform/icons/src/nodes/pluginUpdate_dark.png b/platform/icons/src/nodes/pluginUpdate_dark.png Binary files differnew file mode 100644 index 000000000000..aa051df7a17c --- /dev/null +++ b/platform/icons/src/nodes/pluginUpdate_dark.png diff --git a/platform/indexing-api/src/com/intellij/util/indexing/DefaultFileTypeSpecificInputFilter.java b/platform/indexing-api/src/com/intellij/util/indexing/DefaultFileTypeSpecificInputFilter.java index 6273968c678f..903c5c4992be 100644 --- a/platform/indexing-api/src/com/intellij/util/indexing/DefaultFileTypeSpecificInputFilter.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/DefaultFileTypeSpecificInputFilter.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. @@ -32,7 +32,7 @@ public class DefaultFileTypeSpecificInputFilter implements FileBasedIndex.FileTy } @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return true; } } diff --git a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java index 3cdb853b6d95..6628f3c9225e 100644 --- a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -137,7 +137,7 @@ public abstract class FileBasedIndex implements BaseComponent { * @param project it is guaranteed to return data which is up-to-date withing the project * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist */ - public abstract <K> boolean processAllKeys(@NotNull ID<K, ?> indexId, Processor<K> processor, @Nullable Project project); + public abstract <K> boolean processAllKeys(@NotNull ID<K, ?> indexId, @NotNull Processor<K> processor, @Nullable Project project); public <K> boolean processAllKeys(@NotNull ID<K, ?> indexId, @NotNull Processor<K> processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) { return processAllKeys(indexId, processor, scope.getProject()); @@ -156,7 +156,7 @@ public abstract class FileBasedIndex implements BaseComponent { * Author: dmitrylomov */ public interface InputFilter { - boolean acceptInput(VirtualFile file); + boolean acceptInput(@NotNull VirtualFile file); } public interface FileTypeSpecificInputFilter extends InputFilter { diff --git a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndexExtension.java b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndexExtension.java index 91d9470bbc61..dc6091964163 100644 --- a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndexExtension.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndexExtension.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. @@ -39,11 +39,14 @@ public abstract class FileBasedIndexExtension<K, V> { @NotNull public abstract DataIndexer<K, V, FileContent> getIndexer(); - + + @NotNull public abstract KeyDescriptor<K> getKeyDescriptor(); - + + @NotNull public abstract DataExternalizer<V> getValueExternalizer(); - + + @NotNull public abstract FileBasedIndex.InputFilter getInputFilter(); public abstract boolean dependsOnFileContent(); diff --git a/platform/indexing-impl/src/com/intellij/openapi/module/impl/ModuleScopeProviderImpl.java b/platform/indexing-impl/src/com/intellij/openapi/module/impl/ModuleScopeProviderImpl.java index f90fe7876987..052c73022d53 100644 --- a/platform/indexing-impl/src/com/intellij/openapi/module/impl/ModuleScopeProviderImpl.java +++ b/platform/indexing-impl/src/com/intellij/openapi/module/impl/ModuleScopeProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,8 +31,7 @@ public class ModuleScopeProviderImpl implements ModuleScopeProvider { private GlobalSearchScope myModuleWithDependentsScope; private GlobalSearchScope myModuleTestsWithDependentsScope; - - public ModuleScopeProviderImpl(Module module) { + public ModuleScopeProviderImpl(@NotNull Module module) { myModule = module; } @@ -47,53 +46,72 @@ public class ModuleScopeProviderImpl implements ModuleScopeProvider { } + @Override + @NotNull public GlobalSearchScope getModuleScope() { return getCachedScope(ModuleWithDependenciesScope.COMPILE | ModuleWithDependenciesScope.TESTS); } + @NotNull @Override public GlobalSearchScope getModuleScope(boolean includeTests) { return getCachedScope(ModuleWithDependenciesScope.COMPILE | (includeTests ? ModuleWithDependenciesScope.TESTS : 0)); } + @Override + @NotNull public GlobalSearchScope getModuleWithLibrariesScope() { return getCachedScope(ModuleWithDependenciesScope.COMPILE | ModuleWithDependenciesScope.TESTS | ModuleWithDependenciesScope.LIBRARIES); } + @Override + @NotNull public GlobalSearchScope getModuleWithDependenciesScope() { return getCachedScope(ModuleWithDependenciesScope.COMPILE | ModuleWithDependenciesScope.TESTS | ModuleWithDependenciesScope.MODULES); } + @NotNull @Override public GlobalSearchScope getModuleContentScope() { return getCachedScope(ModuleWithDependenciesScope.CONTENT); } + @NotNull @Override public GlobalSearchScope getModuleContentWithDependenciesScope() { return getCachedScope(ModuleWithDependenciesScope.CONTENT | ModuleWithDependenciesScope.MODULES); } + @Override + @NotNull public GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(boolean includeTests) { return getCachedScope(ModuleWithDependenciesScope.COMPILE | ModuleWithDependenciesScope.MODULES | ModuleWithDependenciesScope.LIBRARIES | (includeTests ? ModuleWithDependenciesScope.TESTS : 0)); } + @Override + @NotNull public GlobalSearchScope getModuleWithDependentsScope() { - if (myModuleWithDependentsScope == null) { - myModuleWithDependentsScope = new ModuleWithDependentsScope(myModule, false); + GlobalSearchScope scope = myModuleWithDependentsScope; + if (scope == null) { + myModuleWithDependentsScope = scope = new ModuleWithDependentsScope(myModule, false); } - return myModuleWithDependentsScope; + return scope; } + @Override + @NotNull public GlobalSearchScope getModuleTestsWithDependentsScope() { - if (myModuleTestsWithDependentsScope == null) { - myModuleTestsWithDependentsScope = new ModuleWithDependentsScope(myModule, true); + GlobalSearchScope scope = myModuleTestsWithDependentsScope; + if (scope == null) { + myModuleTestsWithDependentsScope = scope = new ModuleWithDependentsScope(myModule, true); } - return myModuleTestsWithDependentsScope; + return scope; } + @Override + @NotNull public GlobalSearchScope getModuleRuntimeScope(boolean includeTests) { return getCachedScope( ModuleWithDependenciesScope.MODULES | ModuleWithDependenciesScope.LIBRARIES | (includeTests ? ModuleWithDependenciesScope.TESTS : 0)); diff --git a/platform/indexing-impl/src/com/intellij/openapi/module/impl/scopes/ModuleWithDependenciesScope.java b/platform/indexing-impl/src/com/intellij/openapi/module/impl/scopes/ModuleWithDependenciesScope.java index 0839c80eeb23..477a04f1d549 100644 --- a/platform/indexing-impl/src/com/intellij/openapi/module/impl/scopes/ModuleWithDependenciesScope.java +++ b/platform/indexing-impl/src/com/intellij/openapi/module/impl/scopes/ModuleWithDependenciesScope.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. @@ -54,7 +54,7 @@ public class ModuleWithDependenciesScope extends GlobalSearchScope { private final Set<Module> myModules; private final TObjectIntHashMap<VirtualFile> myRoots = new TObjectIntHashMap<VirtualFile>(); - public ModuleWithDependenciesScope(Module module, @ScopeConstant int options) { + public ModuleWithDependenciesScope(@NotNull Module module, @ScopeConstant int options) { super(module.getProject()); myModule = module; myOptions = options; diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java index 4ad94f5865fc..3e96882ddea1 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.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. @@ -43,19 +43,19 @@ public class IdIndex extends FileBasedIndexExtension<IdIndexEntry, Integer> { private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return isIndexable(file.getFileType()); } }; private final DataExternalizer<Integer> myValueExternalizer = new DataExternalizer<Integer>() { @Override - public void save(final DataOutput out, final Integer value) throws IOException { + public void save(@NotNull final DataOutput out, final Integer value) throws IOException { out.writeByte(value.intValue()); } @Override - public Integer read(final DataInput in) throws IOException { + public Integer read(@NotNull final DataInput in) throws IOException { return Integer.valueOf(in.readByte()); } }; @@ -107,16 +107,19 @@ public class IdIndex extends FileBasedIndexExtension<IdIndexEntry, Integer> { return myIndexer; } + @NotNull @Override public DataExternalizer<Integer> getValueExternalizer() { return myValueExternalizer; } + @NotNull @Override public KeyDescriptor<IdIndexEntry> getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; diff --git a/platform/indexing-impl/src/com/intellij/psi/search/FileTypeIndex.java b/platform/indexing-impl/src/com/intellij/psi/search/FileTypeIndex.java index b0a8673ec6ed..061100b77470 100644 --- a/platform/indexing-impl/src/com/intellij/psi/search/FileTypeIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/search/FileTypeIndex.java @@ -1,3 +1,18 @@ +/* + * 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. + * 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.psi.search; import com.intellij.openapi.fileTypes.FileType; @@ -47,11 +62,13 @@ public class FileTypeIndex extends ScalarIndexExtension<FileType> return this; } + @NotNull @Override public KeyDescriptor<FileType> getKeyDescriptor() { return this; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return this; @@ -73,17 +90,17 @@ public class FileTypeIndex extends ScalarIndexExtension<FileType> } @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return !file.isDirectory(); } @Override - public void save(DataOutput out, FileType value) throws IOException { + public void save(@NotNull DataOutput out, FileType value) throws IOException { myEnumeratorStringDescriptor.save(out, value.getName()); } @Override - public FileType read(DataInput in) throws IOException { + public FileType read(@NotNull DataInput in) throws IOException { String read = myEnumeratorStringDescriptor.read(in); return myFileTypeManager.findFileTypeByName(read); } diff --git a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java index 7c42954efe82..0e95aefcc0bb 100644 --- a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.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. @@ -54,11 +54,13 @@ public class FilenameIndex extends ScalarIndexExtension<String> { return myDataIndexer; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; @@ -156,7 +158,7 @@ public class FilenameIndex extends ScalarIndexExtension<String> { private static class MyInputFilter implements FileBasedIndex.InputFilter { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return true; } } diff --git a/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java b/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java index df1550082dd7..38321417c29e 100644 --- a/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java +++ b/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.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. @@ -17,6 +17,7 @@ package com.intellij.util.indexing; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; @@ -31,6 +32,7 @@ public abstract class ScalarIndexExtension<K> extends FileBasedIndexExtension<K, public static final DataExternalizer<Void> VOID_DATA_EXTERNALIZER = new VoidDataExternalizer(); + @NotNull @Override public final DataExternalizer<Void> getValueExternalizer() { return VOID_DATA_EXTERNALIZER; @@ -39,12 +41,12 @@ public abstract class ScalarIndexExtension<K> extends FileBasedIndexExtension<K, private static class VoidDataExternalizer implements DataExternalizer<Void> { @Override - public void save(final DataOutput out, final Void value) throws IOException { + public void save(@NotNull final DataOutput out, final Void value) throws IOException { } @Override @Nullable - public Void read(final DataInput in) throws IOException { + public Void read(@NotNull final DataInput in) throws IOException { return null; } } diff --git a/platform/indexing-impl/src/com/intellij/util/indexing/SingleEntryFileBasedIndexExtension.java b/platform/indexing-impl/src/com/intellij/util/indexing/SingleEntryFileBasedIndexExtension.java index 128d7d40d4fe..1e111b2d01de 100644 --- a/platform/indexing-impl/src/com/intellij/util/indexing/SingleEntryFileBasedIndexExtension.java +++ b/platform/indexing-impl/src/com/intellij/util/indexing/SingleEntryFileBasedIndexExtension.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. @@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull; * Date: Feb 18, 2009 */ public abstract class SingleEntryFileBasedIndexExtension<V> extends FileBasedIndexExtension<Integer, V>{ + @NotNull @Override public final KeyDescriptor<Integer> getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ClickNavigator.java b/platform/lang-impl/src/com/intellij/application/options/colors/ClickNavigator.java index 464bf038d986..df10c20fe536 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ClickNavigator.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ClickNavigator.java @@ -1,6 +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. @@ -25,6 +24,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.HighlighterColors; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.editor.event.CaretAdapter; import com.intellij.openapi.editor.event.CaretEvent; import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.editor.ex.EditorEx; @@ -56,7 +56,7 @@ public class ClickNavigator { } }); - CaretListener listener = new CaretListener() { + CaretListener listener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { setSelectedItem(HighlighterColors.TEXT.getExternalName(), true); @@ -98,7 +98,7 @@ public class ClickNavigator { final boolean isBackgroundImportant) { addMouseMotionListener(view, highlighter, data, isBackgroundImportant); - CaretListener listener = new CaretListener() { + CaretListener listener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { navigate(view, true, e.getNewPosition(), highlighter, data, isBackgroundImportant); diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/SimpleEditorPreview.java b/platform/lang-impl/src/com/intellij/application/options/colors/SimpleEditorPreview.java index 6daa2db58134..e7e92ca98401 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/SimpleEditorPreview.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/SimpleEditorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.colors.CodeInsightColors; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.editor.event.CaretAdapter; import com.intellij.openapi.editor.event.CaretEvent; import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.editor.ex.EditorEx; @@ -80,7 +81,7 @@ public class SimpleEditorPreview implements PreviewPanel{ if (navigatable) { addMouseMotionListener(myEditor, page.getHighlighter(), myHighlightData, false); - CaretListener listener = new CaretListener() { + CaretListener listener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { navigate(myEditor, true, e.getNewPosition(), page.getHighlighter(), myHighlightData, false); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index a721c6f04aaa..392e35ac5941 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -622,20 +622,26 @@ public class CodeCompletionHandlerBase { marker.dispose(); } - } else { - final Ref<CompletionAssertions.WatchingInsertionContext> contextRef = new Ref<CompletionAssertions.WatchingInsertionContext>(); - final Caret primaryCaret = editor.getCaretModel().getPrimaryCaret(); + } else if (editor.getCaretModel().supportsMultipleCarets()) { + final List<CompletionAssertions.WatchingInsertionContext> contexts = new ArrayList<CompletionAssertions.WatchingInsertionContext>(); editor.getCaretModel().runForEachCaret(new CaretAction() { @Override public void perform(Caret caret) { CompletionAssertions.WatchingInsertionContext currentContext = insertItem(indicator, item, completionChar, items, update, editor, caret.getOffset(), caret.getOffset() + idEndOffsetDelta); - if (caret == primaryCaret) { - contextRef.set(currentContext); - } + contexts.add(currentContext); } }); - context = contextRef.get(); + context = contexts.get(contexts.size() - 1); + if (context.shouldAddCompletionChar() && context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR) { + DataContext dataContext = DataManager.getInstance().getDataContext(editor.getContentComponent()); + EditorActionManager.getInstance().getTypedAction().getHandler().execute(editor, completionChar, dataContext); + } + for (CompletionAssertions.WatchingInsertionContext insertionContext : contexts) { + insertionContext.stopWatching(); + } + } else { + context = insertItem(indicator, item, completionChar, items, update, editor, caretOffset, idEndOffset); } return context; } @@ -719,7 +725,9 @@ public class CodeCompletionHandlerBase { if (context.shouldAddCompletionChar()) { addCompletionChar(project, context, item, editor, indicator, completionChar); } - context.stopWatching(); + if (!editor.getCaretModel().supportsMultipleCarets()) { // done later, outside of this method + context.stopWatching(); + } editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } }); @@ -747,7 +755,7 @@ public class CodeCompletionHandlerBase { } } } - else { + else if (!editor.getCaretModel().supportsMultipleCarets()) { // this will be done outside of runForEach caret context DataContext dataContext = DataManager.getInstance().getDataContext(editor.getContentComponent()); EditorActionManager.getInstance().getTypedAction().getHandler().execute(editor, completionChar, dataContext); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java index 6ba44fde4fdc..d135e19f9e52 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.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. @@ -253,7 +253,7 @@ public abstract class CompletionPhase implements Disposable { CompletionServiceImpl.setCompletionPhase(NoCompletion); } }; - final CaretListener caretListener = new CaretListener() { + final CaretListener caretListener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { CompletionServiceImpl.setCompletionPhase(NoCompletion); @@ -341,7 +341,7 @@ public abstract class CompletionPhase implements Disposable { } }; - caretListener = new CaretListener() { + caretListener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { if (!TypedAction.isTypedActionInProgress()) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java index d20e48149b1c..b33a029cc7c3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java @@ -176,7 +176,7 @@ public class DaemonListeners implements Disposable { } }, this); - eventMulticaster.addCaretListener(new CaretListener() { + eventMulticaster.addCaretListener(new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { final Editor editor = e.getEditor(); @@ -184,17 +184,17 @@ public class DaemonListeners implements Disposable { !worthBothering(editor.getDocument(), editor.getProject())) { return; //no need to stop daemon if something happened in the console } - - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (!editor.getComponent().isShowing() && !application.isUnitTestMode() || - myProject.isDisposed()) { - return; + if (!application.isUnitTestMode()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (!editor.getComponent().isShowing() || myProject.isDisposed()) { + return; + } + myDaemonCodeAnalyzer.hideLastIntentionHint(); } - myDaemonCodeAnalyzer.hideLastIntentionHint(); - } - }, ModalityState.current()); + }, ModalityState.current()); + } } }, this); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java index 89e8b55f9b4c..199f66732699 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.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. @@ -354,7 +354,7 @@ public class QuickDocOnMouseOverManager { } } - private class MyCaretListener implements CaretListener { + private class MyCaretListener extends CaretAdapter { @Override public void caretPositionChanged(CaretEvent e) { allowUpdateFromContext(true); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java index 9c15f4ffde8a..0296e8e139dc 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java @@ -90,7 +90,7 @@ public class PasteHandler extends EditorActionHandler implements EditorTextInser final Project project = editor.getProject(); if (project == null || editor.isColumnMode() || editor.getSelectionModel().hasBlockSelection() - || editor.getCaretModel().getAllCarets().size() > 1) { + || editor.getCaretModel().getCaretCount() > 1) { if (myOriginalHandler != null) { myOriginalHandler.execute(editor, context); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java index 216227d7744c..259fe9766fb1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java @@ -135,10 +135,7 @@ public class TypedHandler extends TypedActionHandlerBase { Project project = CommonDataKeys.PROJECT.getData(dataContext); PsiFile file; - if (project == null - || editor.isColumnMode() - || editor.getCaretModel().getAllCarets().size() > 1 - || (file = PsiUtilBase.getPsiFileInEditor(editor, project)) == null) { + if (project == null || editor.isColumnMode() || (file = PsiUtilBase.getPsiFileInEditor(editor, project)) == null) { if (myOriginalHandler != null){ myOriginalHandler.execute(editor, charTyped, dataContext); } @@ -174,13 +171,13 @@ public class TypedHandler extends TypedActionHandlerBase { } if (!editor.isInsertMode()){ - myOriginalHandler.execute(originalEditor, charTyped, dataContext); + if (myOriginalHandler != null) { + myOriginalHandler.execute(originalEditor, charTyped, dataContext); + } return; } - if (editor.getSelectionModel().hasSelection()){ - EditorModificationUtil.deleteSelectedText(editor); - } + EditorModificationUtil.deleteSelectedTextForAllCarets(editor); FileType fileType = getFileType(file, editor); @@ -194,7 +191,7 @@ public class TypedHandler extends TypedActionHandlerBase { } } - if (!editor.getSelectionModel().hasBlockSelection()) { + if (!editor.getSelectionModel().hasBlockSelection() && editor.getCaretModel().getCaretCount() == 1) { if (')' == charTyped || ']' == charTyped || '}' == charTyped) { if (FileTypes.PLAIN_TEXT != fileType) { if (handleRParen(editor, fileType, charTyped)) return; @@ -206,12 +203,14 @@ public class TypedHandler extends TypedActionHandlerBase { } long modificationStampBeforeTyping = editor.getDocument().getModificationStamp(); - myOriginalHandler.execute(originalEditor, charTyped, dataContext); + if (myOriginalHandler != null) { + myOriginalHandler.execute(originalEditor, charTyped, dataContext); + } AutoHardWrapHandler.getInstance().wrapLineIfNecessary(editor, dataContext, modificationStampBeforeTyping); if (('(' == charTyped || '[' == charTyped || '{' == charTyped) && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET && - !editor.getSelectionModel().hasBlockSelection() && fileType != FileTypes.PLAIN_TEXT) { + !editor.getSelectionModel().hasBlockSelection() && editor.getCaretModel().getCaretCount() == 1 && fileType != FileTypes.PLAIN_TEXT) { handleAfterLParen(editor, fileType, charTyped); } else if ('}' == charTyped) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java index 48c1dfbef792..524a2b2f286a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java @@ -83,15 +83,7 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter { myWorksWithFormatter = worksWithFormatter; } - @Override - public Result preprocessEnter( - @NotNull final PsiFile file, - @NotNull final Editor editor, - @NotNull final Ref<Integer> caretOffset, - @NotNull final Ref<Integer> caretAdvance, - @NotNull final DataContext dataContext, - final EditorActionHandler originalHandler) - { + protected Result shouldSkipWithResult(@NotNull final PsiFile file, @NotNull final Editor editor, @NotNull final DataContext dataContext) { final Project project = CommonDataKeys.PROJECT.getData(dataContext); if (project == null) { return Result.Continue; @@ -119,7 +111,25 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter { if (caret <= 0) { return Result.Continue; } + return null; + } + + @Override + public Result preprocessEnter( + @NotNull final PsiFile file, + @NotNull final Editor editor, + @NotNull final Ref<Integer> caretOffset, + @NotNull final Ref<Integer> caretAdvance, + @NotNull final DataContext dataContext, + final EditorActionHandler originalHandler) + { + Result res = shouldSkipWithResult(file, editor, dataContext); + if (res != null) { + return res; + } + final Document document = editor.getDocument(); + int caret = editor.getCaretModel().getOffset(); final int lineNumber = document.getLineNumber(caret); final int lineStartOffset = document.getLineStartOffset(lineNumber); @@ -207,7 +217,7 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter { } @Nullable - private IElementType getNonWhitespaceElementType(final HighlighterIterator iterator, int currentLineStartOffset, final int prevLineStartOffset) { + protected IElementType getNonWhitespaceElementType(final HighlighterIterator iterator, int currentLineStartOffset, final int prevLineStartOffset) { while (!iterator.atEnd() && iterator.getEnd() >= currentLineStartOffset && iterator.getStart() >= prevLineStartOffset) { final IElementType tokenType = iterator.getTokenType(); if (!myWhitespaceTokens.contains(tokenType)) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java index 026564d7d2a0..a965a850b2fa 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java @@ -39,7 +39,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.ui.LightweightHint; import com.intellij.util.containers.WeakList; -import com.intellij.util.ui.UIUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -184,7 +183,7 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec @Override public void releaseFoldings(@NotNull Editor editor) { - ApplicationManager.getApplication().assertIsDispatchThread(); + ApplicationManagerEx.getApplicationEx().assertIsDispatchThread(editor.getComponent()); final Project project = editor.getProject(); if (project != null && (!project.equals(myProject) || !project.isOpen())) return; @@ -217,32 +216,26 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec PsiDocumentManager.getInstance(myProject).commitDocument(document); - Runnable operation = new Runnable() { + Runnable runnable = updateFoldRegions(editor, true, true); + if (runnable != null) { + runnable.run(); + } + if (myProject.isDisposed() || editor.isDisposed()) return; + foldingModel.runBatchFoldingOperation(new Runnable() { @Override public void run() { - Runnable runnable = updateFoldRegions(editor, true, true); - if (runnable != null) { - runnable.run(); + DocumentFoldingInfo documentFoldingInfo = getDocumentFoldingInfo(document); + Editor[] editors = EditorFactory.getInstance().getEditors(document, myProject); + for (Editor otherEditor : editors) { + if (otherEditor == editor) continue; + documentFoldingInfo.loadFromEditor(otherEditor); + break; } - if (myProject.isDisposed() || editor.isDisposed()) return; - foldingModel.runBatchFoldingOperation(new Runnable() { - @Override - public void run() { - DocumentFoldingInfo documentFoldingInfo = getDocumentFoldingInfo(document); - Editor[] editors = EditorFactory.getInstance().getEditors(document, myProject); - for (Editor otherEditor : editors) { - if (otherEditor == editor) continue; - documentFoldingInfo.loadFromEditor(otherEditor); - break; - } - documentFoldingInfo.setToEditor(editor); + documentFoldingInfo.setToEditor(editor); - documentFoldingInfo.clear(); - } - }); + documentFoldingInfo.clear(); } - }; - UIUtil.invokeLaterIfNeeded(operation); + }); } @Override diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java index 0e420b04de2d..9294f108eb75 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java @@ -21,6 +21,7 @@ import com.intellij.lang.folding.FoldingBuilder; import com.intellij.lang.folding.FoldingDescriptor; import com.intellij.lang.folding.LanguageFolding; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -38,7 +39,6 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import javax.swing.*; import java.util.*; class DocumentFoldingInfo implements JDOMExternalizable, CodeFoldingState { @@ -64,7 +64,7 @@ class DocumentFoldingInfo implements JDOMExternalizable, CodeFoldingState { } void loadFromEditor(@NotNull Editor editor) { - assertDispatchThread(); + assertDispatchThread(editor); LOG.assertTrue(!editor.isDisposed()); clear(); @@ -95,12 +95,12 @@ class DocumentFoldingInfo implements JDOMExternalizable, CodeFoldingState { } } - private static void assertDispatchThread() { - assert SwingUtilities.isEventDispatchThread() : Thread.currentThread(); + private static void assertDispatchThread(@NotNull Editor editor) { + ApplicationManagerEx.getApplicationEx().assertIsDispatchThread(editor.getComponent()); } void setToEditor(@NotNull final Editor editor) { - assertDispatchThread(); + assertDispatchThread(editor); final PsiManager psiManager = PsiManager.getInstance(myProject); if (psiManager.isDisposed()) return; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlighter.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlighter.java index 597610416c9f..52b955ef73c7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlighter.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlighter.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. @@ -42,7 +42,7 @@ public class BraceHighlighter implements StartupActivity { public void runActivity(@NotNull final Project project) { final EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster(); - CaretListener myCaretListener = new CaretListener() { + CaretListener myCaretListener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { myAlarm.cancelAllRequests(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java index 77944cfd7e30..237d55118a5f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java @@ -251,19 +251,24 @@ public class ParameterInfoComponent extends JPanel { int lineOffset = 0; + boolean hasHighlighting = highlightStartOffset >= 0 && highlightEndOffset > highlightStartOffset; + TextRange highlightingRange = hasHighlighting ? new TextRange(highlightStartOffset, highlightEndOffset) : null; + for (int i = 0; i < lines.length; i++) { - String line = escapeString(lines[i]); + String line = lines[i]; myOneLineComponents[i] = new OneLineComponent(); - TextRange range = null; - if (highlightStartOffset >= 0 && highlightEndOffset > lineOffset && highlightStartOffset < lineOffset + line.length()) { - int startOffset = Math.max(highlightStartOffset - lineOffset, 0); - int endOffset = Math.min(highlightEndOffset - lineOffset, line.length()); - range = TextRange.create(startOffset, endOffset); - } + TextRange lRange = new TextRange(lineOffset, lineOffset + line.length()); + TextRange hr = highlightingRange == null ? null : lRange.intersection(highlightingRange); + hr = hr == null ? null : hr.shiftRight(-lineOffset); + + String before = escapeString(hr == null ? line : line.substring(0, hr.getStartOffset())); + String in = hr == null ? "" : escapeString(hr.substring(line)); + String after = hr == null ? "" : escapeString(line.substring(hr.getEndOffset(), line.length())); - buf.append(myOneLineComponents[i].setup(line, isDisabled, strikeout, background, range)); + TextRange escapedHighlightingRange = in.isEmpty() ? null : TextRange.create(before.length(), before.length() + in.length()); + buf.append(myOneLineComponents[i].setup(before + in + after, isDisabled, strikeout, background, escapedHighlightingRange)); if (isDisabledBeforeHighlight) { if (highlightStartOffset < 0 || highlightEndOffset > lineOffset) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java index 533562858621..73ad86b2fa72 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.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. @@ -25,10 +25,7 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.editor.event.CaretEvent; -import com.intellij.openapi.editor.event.CaretListener; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; @@ -177,7 +174,7 @@ public class ParameterInfoController implements Disposable { List<ParameterInfoController> allControllers = getAllControllers(myEditor); allControllers.add(this); - myEditorCaretListener = new CaretListener(){ + myEditorCaretListener = new CaretAdapter(){ @Override public void caretPositionChanged(CaretEvent e) { myAlarm.cancelAllRequests(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java index 114d493898cc..b50395009c34 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java @@ -117,10 +117,15 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable { final String newFileName = StringUtil.notNullize(language.getDisplayName(), "Injected") + " Fragment " + "(" + origFile.getName() + ":" + shreds.get(0).getHost().getTextRange().getStartOffset() + ")" + "." + fileType.getDefaultExtension(); + + // preserve \r\n as it is done in MultiHostRegistrarImpl myNewFile = factory.createFileFromText(newFileName, language, text, true, true); - myNewVirtualFile = (LightVirtualFile)myNewFile.getVirtualFile(); + myNewVirtualFile = ObjectUtils.assertNotNull((LightVirtualFile)myNewFile.getVirtualFile()); + myNewVirtualFile.setOriginalFile(origFile.getVirtualFile()); + + assert myNewFile != null : "PSI file is null"; + assert myNewFile.getTextLength() == myNewVirtualFile.getLength() : "PSI / Virtual file text mismatch"; myNewVirtualFile.setOriginalFile(origFile.getVirtualFile()); - assert myNewVirtualFile != null; // suppress possible errors as in injected mode myNewFile.putUserData(InjectedLanguageUtil.FRANKENSTEIN_INJECTION, injectedFile.getUserData(InjectedLanguageUtil.FRANKENSTEIN_INJECTION)); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index 26115d4b307e..cecdce57dad0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -868,7 +868,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable } }, this); - final CaretListener caretListener = new CaretListener() { + final CaretListener caretListener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { if (!myChangeGuard && !myFinishing) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java index be95eed73160..9d8c67938907 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.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. @@ -80,7 +80,7 @@ public class LookupTypedHandler extends TypedHandlerDelegate { if (!lookup.performGuardedChange(new Runnable() { @Override public void run() { - EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(editor, String.valueOf(charTyped), true); + EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, String.valueOf(charTyped), true); } })) { return Result.STOP; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java index 3e0e26424bb5..1ee91b8212b8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.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. @@ -250,7 +250,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent { EditorEventMulticaster eventMulticaster = editorFactory.getEventMulticaster(); eventMulticaster.addEditorMouseListener(myEditorMouseAdapter, project); eventMulticaster.addEditorMouseMotionListener(myEditorMouseMotionListener, project); - eventMulticaster.addCaretListener(new CaretListener() { + eventMulticaster.addCaretListener(new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { if (myHint != null) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/IncrementalSearchHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/IncrementalSearchHandler.java index 36e5d2988029..fc0aed021ceb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/IncrementalSearchHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/IncrementalSearchHandler.java @@ -170,7 +170,7 @@ public class IncrementalSearchHandler { }; document.addDocumentListener(documentListener[0]); - caretListener[0] = new CaretListener() { + caretListener[0] = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { PerHintSearchData data = hint.getUserData(SEARCH_DATA_IN_HINT_KEY); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 72d6d056080d..d3f658cdcf24 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -34,10 +34,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.event.CaretEvent; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.MultipleCaretListener; +import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.markup.HighlighterLayer; import com.intellij.openapi.editor.markup.HighlighterTargetArea; @@ -86,7 +83,7 @@ public class TemplateState implements Disposable { private boolean myDocumentChanged = false; @Nullable private CommandAdapter myCommandListener; - @Nullable private MultipleCaretListener myCaretListener; + @Nullable private CaretListener myCaretListener; private final List<TemplateEditingListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private DocumentAdapter myEditorDocumentListener; @@ -146,7 +143,7 @@ public class TemplateState implements Disposable { } }; - myCaretListener = new MultipleCaretListener() { + myCaretListener = new CaretAdapter() { @Override public void caretAdded(CaretEvent e) { if (isMultiCaretMode()) { @@ -160,9 +157,6 @@ public class TemplateState implements Disposable { finishTemplateEditing(false); } } - - @Override - public void caretPositionChanged(CaretEvent e) {} }; if (myEditor != null) { @@ -173,7 +167,7 @@ public class TemplateState implements Disposable { } private boolean isMultiCaretMode() { - return myEditor != null && myEditor.getCaretModel().supportsMultipleCarets() && myEditor.getCaretModel().getAllCarets().size() > 1; + return myEditor != null && myEditor.getCaretModel().getCaretCount() > 1; } @Override diff --git a/platform/lang-impl/src/com/intellij/execution/actions/StopProcessAction.java b/platform/lang-impl/src/com/intellij/execution/actions/StopProcessAction.java index e38cac95243c..652ea0871215 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/StopProcessAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/StopProcessAction.java @@ -32,13 +32,17 @@ import javax.swing.*; */ public class StopProcessAction extends DumbAwareAction implements AnAction.TransparentUpdate { - private final ProcessHandler myProcessHandler; + private ProcessHandler myProcessHandler; - public StopProcessAction(@NotNull String text, @Nullable String description, @NotNull ProcessHandler processHandler) { + public StopProcessAction(@NotNull String text, @Nullable String description, @Nullable ProcessHandler processHandler) { super(text, description, AllIcons.Actions.Suspend); myProcessHandler = processHandler; } + public void setProcessHandler(@Nullable ProcessHandler processHandler) { + myProcessHandler = processHandler; + } + @Override public void update(final AnActionEvent e) { update(e.getPresentation(), getTemplatePresentation(), myProcessHandler); @@ -72,7 +76,7 @@ public class StopProcessAction extends DumbAwareAction implements AnAction.Trans stopProcess(myProcessHandler); } - public static void stopProcess(@NotNull ProcessHandler processHandler) { + public static void stopProcess(@Nullable ProcessHandler processHandler) { if (processHandler instanceof KillableProcess && processHandler.isProcessTerminating()) { // process termination was requested, but it's still alive // in this case 'force quit' will be performed @@ -80,11 +84,13 @@ public class StopProcessAction extends DumbAwareAction implements AnAction.Trans return; } - if (processHandler.detachIsDefault()) { - processHandler.detachProcess(); - } - else { - processHandler.destroyProcess(); + if (processHandler != null) { + if (processHandler.detachIsDefault()) { + processHandler.detachProcess(); + } + else { + processHandler.destroyProcess(); + } } } diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java index 9f8900eacbdd..bcb78d83ae64 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java @@ -24,10 +24,12 @@ import com.intellij.openapi.actionSystem.EmptyAction; import com.intellij.openapi.command.impl.UndoManagerImpl; import com.intellij.openapi.command.undo.DocumentReferenceManager; import com.intellij.openapi.command.undo.UndoManager; +import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -110,23 +112,39 @@ public class ConsoleExecuteAction extends DumbAwareAction { myExecuteActionHandler.runExecuteAction(myConsole, myConsoleView); } - protected boolean isEnabled() { + public boolean isEnabled() { return myEnabledCondition.value(myConsole); } + public void execute(@Nullable TextRange range, @NotNull String text, @Nullable EditorEx editor) { + if (range == null) { + myConsole.doAddPromptToHistory(); + DocumentEx document = myConsole.getHistoryViewer().getDocument(); + document.insertString(document.getTextLength(), text); + if (!text.endsWith("\n")) { + document.insertString(document.getTextLength(), "\n"); + } + } + else { + assert editor != null; + myConsole.addTextRangeToHistory(range, editor, myExecuteActionHandler.myPreserveMarkup); + } + myExecuteActionHandler.addToCommandHistoryAndExecute(myConsole, myConsoleView, text); + } + static abstract class ConsoleExecuteActionHandler { - private final ConsoleHistoryModel myConsoleHistoryModel; + private final ConsoleHistoryModel myCommandHistoryModel; private boolean myAddToHistory = true; final boolean myPreserveMarkup; public ConsoleExecuteActionHandler(boolean preserveMarkup) { - myConsoleHistoryModel = new ConsoleHistoryModel(); + myCommandHistoryModel = new ConsoleHistoryModel(); myPreserveMarkup = preserveMarkup; } public ConsoleHistoryModel getConsoleHistoryModel() { - return myConsoleHistoryModel; + return myCommandHistoryModel; } public boolean isEmptyCommandExecutionAllowed() { @@ -139,10 +157,12 @@ public class ConsoleExecuteAction extends DumbAwareAction { final void runExecuteAction(@NotNull LanguageConsoleImpl console, @Nullable LanguageConsoleView consoleView) { String text = console.prepareExecuteAction(myAddToHistory, myPreserveMarkup, true); - ((UndoManagerImpl)UndoManager.getInstance(console.getProject())).invalidateActionsFor(DocumentReferenceManager.getInstance().create(console.getCurrentEditor().getDocument())); + addToCommandHistoryAndExecute(console, consoleView, text); + } - myConsoleHistoryModel.addToHistory(text); + private void addToCommandHistoryAndExecute(@NotNull LanguageConsoleImpl console, @Nullable LanguageConsoleView consoleView, @NotNull String text) { + myCommandHistoryModel.addToHistory(text); doExecute(text, console, consoleView); } diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleGutterComponent.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleGutterComponent.java index f7a1d6cc80fd..e9881c3b6007 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleGutterComponent.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleGutterComponent.java @@ -3,8 +3,6 @@ package com.intellij.execution.console; import com.intellij.codeInsight.hint.TooltipController; import com.intellij.codeInsight.hint.TooltipGroup; import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.impl.ApplicationImpl; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.VisualPosition; import com.intellij.openapi.editor.colors.EditorFontType; @@ -29,27 +27,38 @@ class ConsoleGutterComponent extends JComponent implements MouseMotionListener { private final EditorImpl editor; - private int maxAnnotationWidth = 0; + private int maxContentWidth; private int myLastPreferredHeight = -1; - private final int lineEndInset; + private final int gap; private final GutterContentProvider gutterContentProvider; private int lastGutterToolTipLine = -1; - public ConsoleGutterComponent(@NotNull Editor editor, @NotNull GutterContentProvider provider) { - this.editor = (EditorImpl)editor; - gutterContentProvider = provider; - addListeners(); + private final boolean atLineStart; - addMouseMotionListener(this); + public ConsoleGutterComponent(@NotNull Editor editor, @NotNull GutterContentProvider gutterContentProvider, boolean atLineStart) { + this.editor = (EditorImpl)editor; + this.gutterContentProvider = gutterContentProvider; + this.atLineStart = atLineStart; - setOpaque(true); + if (atLineStart) { + setOpaque(gutterContentProvider.getLineStartGutterOverlap(editor) == 0); + } + else { + addListeners(); + setOpaque(false); + } - lineEndInset = EditorUtil.getSpaceWidth(Font.PLAIN, editor); + int spaceWidth = EditorUtil.getSpaceWidth(Font.PLAIN, editor); + // at line start: icon/one-char symbol + space + gap = atLineStart ? spaceWidth * GutterContentProvider.MAX_LINE_END_GUTTER_WIDTH_IN_CHAR : spaceWidth; + maxContentWidth = atLineStart ? gap : 0; } private void addListeners() { + addMouseMotionListener(this); + addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -61,9 +70,9 @@ class ConsoleGutterComponent extends JComponent implements MouseMotionListener { } public void updateSize(int start, int end) { - int oldAnnotationsWidth = maxAnnotationWidth; + int oldAnnotationsWidth = maxContentWidth; computeMaxAnnotationWidth(start, end); - if (oldAnnotationsWidth != maxAnnotationWidth || myLastPreferredHeight != editor.getPreferredHeight()) { + if (oldAnnotationsWidth != maxContentWidth || myLastPreferredHeight != editor.getPreferredHeight()) { processComponentEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED)); } repaint(); @@ -72,8 +81,13 @@ class ConsoleGutterComponent extends JComponent implements MouseMotionListener { private void computeMaxAnnotationWidth(int start, int end) { gutterContentProvider.beforeUiComponentUpdate(editor); + if (atLineStart) { + return; + } + if (!gutterContentProvider.hasText()) { - maxAnnotationWidth = 0; + editor.getSettings().setAdditionalColumnsCount(1); + maxContentWidth = 0; return; } @@ -87,46 +101,51 @@ class ConsoleGutterComponent extends JComponent implements MouseMotionListener { } } + // line start gutter always has gap if (gutterSize != 0) { - gutterSize += lineEndInset; + gutterSize += gap; } - maxAnnotationWidth = Math.max(gutterSize, maxAnnotationWidth); + maxContentWidth = Math.max(gutterSize, maxContentWidth); - editor.getSettings().setAdditionalColumnsCount(1 + (maxAnnotationWidth / EditorUtil.getSpaceWidth(Font.PLAIN, editor))); + editor.getSettings().setAdditionalColumnsCount(1 + (maxContentWidth / EditorUtil.getSpaceWidth(Font.PLAIN, editor))); } @Override public Dimension getPreferredSize() { myLastPreferredHeight = editor.getPreferredHeight(); - return new Dimension(maxAnnotationWidth, myLastPreferredHeight); + return new Dimension(maxContentWidth, myLastPreferredHeight); } @Override public void paint(Graphics g) { - ((ApplicationImpl)ApplicationManager.getApplication()).editorPaintStart(); - try { - Rectangle clip = g.getClipBounds(); - if (clip.height < 0 || maxAnnotationWidth == 0) { + Rectangle clip = g.getClipBounds(); + if (clip.height <= 0 || maxContentWidth == 0) { + return; + } + + if (atLineStart) { + // don't paint in the overlapped region + if (clip.x >= maxContentWidth) { return; } - UISettings.setupAntialiasing(g); + g.setColor(editor.getBackgroundColor()); + g.fillRect(clip.x, clip.y, Math.min(clip.width, maxContentWidth - clip.x), clip.height); + } - Graphics2D g2 = (Graphics2D)g; - Object hint = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); - if (!UIUtil.isRetina()) { - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - } + UISettings.setupAntialiasing(g); - try { - paintAnnotations(g, clip); - } - finally { - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint); - } + Graphics2D g2 = (Graphics2D)g; + Object hint = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); + if (!UIUtil.isRetina()) { + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + } + + try { + paintAnnotations(g, clip); } finally { - ((ApplicationImpl)ApplicationManager.getApplication()).editorPaintFinish(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint); } } @@ -138,17 +157,24 @@ class ConsoleGutterComponent extends JComponent implements MouseMotionListener { return; } - gutterContentProvider.beforeUiComponentUpdate(editor); - - g.setColor(JBColor.BLUE); + if (!atLineStart) { + g.setColor(JBColor.BLUE); + } g.setFont(editor.getColorsScheme().getFont(EditorFontType.PLAIN)); + int y = ((startLine + 1) * lineHeight) - editor.getDescent(); FontMetrics fontMetrics = editor.getFontMetrics(Font.PLAIN); - for (int i = startLine; i < endLine; i++) { - String text = gutterContentProvider.getText(editor.visualToLogicalPosition(new VisualPosition(i, 0)).line, editor); - if (text != null) { - // right-aligned - g.drawString(text, maxAnnotationWidth - lineEndInset - fontMetrics.stringWidth(text), y); + for (int line = startLine; line < endLine; line++) { + int logicalLine = editor.visualToLogicalPosition(new VisualPosition(line, 0)).line; + if (atLineStart) { + gutterContentProvider.drawIcon(logicalLine, g, y, editor); + } + else { + String text = gutterContentProvider.getText(logicalLine, editor); + if (text != null) { + // right-aligned + g.drawString(text, maxContentWidth - gap - fontMetrics.stringWidth(text), y); + } } y += lineHeight; } @@ -190,6 +216,8 @@ class ConsoleGutterComponent extends JComponent implements MouseMotionListener { } public void documentCleared() { - maxAnnotationWidth = 0; + if (!atLineStart) { + maxContentWidth = 0; + } } }
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleIconGutterComponent.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleIconGutterComponent.java deleted file mode 100644 index ec57b2108a71..000000000000 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleIconGutterComponent.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.intellij.execution.console; - -import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.impl.ApplicationImpl; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.VisualPosition; -import com.intellij.openapi.editor.colors.EditorFontType; -import com.intellij.openapi.editor.ex.util.EditorUtil; -import com.intellij.openapi.editor.impl.EditorImpl; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ComponentEvent; - -class ConsoleIconGutterComponent extends JComponent { - private final int iconAreaWidth; - - private int myLastPreferredHeight = -1; - private final EditorImpl editor; - - private final GutterContentProvider gutterContentProvider; - - public ConsoleIconGutterComponent(@NotNull Editor editor, @NotNull GutterContentProvider provider) { - this.editor = (EditorImpl)editor; - gutterContentProvider = provider; - - // icon/one-char symbol + space - iconAreaWidth = EditorUtil.getSpaceWidth(Font.PLAIN, editor) * 2; - } - - public void updateSize() { - if (myLastPreferredHeight != editor.getPreferredHeight()) { - fireResized(); - } - repaint(); - } - - private void fireResized() { - processComponentEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED)); - } - - @Override - public Dimension getPreferredSize() { - myLastPreferredHeight = editor.getPreferredHeight(); - return new Dimension(iconAreaWidth, myLastPreferredHeight); - } - - @Override - public void paint(Graphics g) { - ((ApplicationImpl)ApplicationManager.getApplication()).editorPaintStart(); - try { - Rectangle clip = g.getClipBounds(); - if (clip.height < 0) { - return; - } - - g.setColor(editor.getBackgroundColor()); - g.fillRect(clip.x, clip.y, clip.width, clip.height); - - UISettings.setupAntialiasing(g); - - Graphics2D g2 = (Graphics2D)g; - Object hint = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); - if (!UIUtil.isRetina()) { - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - } - - try { - paintAnnotations(g, clip); - } - finally { - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint); - } - } - finally { - ((ApplicationImpl)ApplicationManager.getApplication()).editorPaintFinish(); - } - } - - private void paintAnnotations(Graphics g, Rectangle clip) { - int lineHeight = editor.getLineHeight(); - int startLine = clip.y / lineHeight; - int endLine = Math.min(((clip.y + clip.height) / lineHeight) + 1, editor.getVisibleLineCount()); - if (startLine >= endLine) { - return; - } - - g.setFont(editor.getColorsScheme().getFont(EditorFontType.PLAIN)); - int y = ((startLine + 1) * lineHeight) - editor.getDescent(); - for (int i = startLine; i < endLine; i++) { - gutterContentProvider.drawIcon(editor.visualToLogicalPosition(new VisualPosition(i, 0)).line, g, y, editor); - y += lineHeight; - } - } -}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/console/GutterContentProvider.java b/platform/lang-impl/src/com/intellij/execution/console/GutterContentProvider.java index c283b1a53fdc..c2eed1a09cd3 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/GutterContentProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/console/GutterContentProvider.java @@ -7,6 +7,8 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; public abstract class GutterContentProvider { + protected static final int MAX_LINE_END_GUTTER_WIDTH_IN_CHAR = 2; + public void beforeUiComponentUpdate(@NotNull Editor editor) { } @@ -31,4 +33,8 @@ public abstract class GutterContentProvider { public boolean isShowSeparatorLine(int line, @NotNull Editor editor) { return true; } + + public int getLineStartGutterOverlap(@NotNull Editor editor) { + return 0; + } }
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java index 0d013fbfec1c..22b82c803c74 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java @@ -147,7 +147,7 @@ public final class LanguageConsoleBuilder { } public LanguageConsoleView build(@NotNull Project project, @NotNull Language language) { - GutteredLanguageConsole console = new GutteredLanguageConsole(project, language, gutterContentProvider, psiFileFactory); + GutteredLanguageConsole console = new GutteredLanguageConsole(language.getDisplayName() + " Console", project, language, gutterContentProvider, psiFileFactory); LanguageConsoleViewImpl consoleView = new LanguageConsoleViewImpl(console, true); if (executeActionHandler != null) { assert historyType != null; @@ -184,11 +184,12 @@ public final class LanguageConsoleBuilder { @Nullable private final PairFunction<VirtualFile, Project, PsiFile> psiFileFactory; - public GutteredLanguageConsole(@NotNull Project project, + public GutteredLanguageConsole(@NotNull String title, + @NotNull Project project, @NotNull Language language, @Nullable GutterContentProvider gutterContentProvider, @Nullable PairFunction<VirtualFile, Project, PsiFile> psiFileFactory) { - super(project, language.getDisplayName() + " Console", language, false); + super(project, title, new LightVirtualFile(title, language, ""), false, psiFileFactory); setShowSeparatorLine(false); @@ -201,6 +202,11 @@ public final class LanguageConsoleBuilder { return gutterContentProvider == null; } + @Override + int getMinHistoryLineCount() { + return 1; + } + @NotNull @Override protected PsiFile createFile(@NotNull LightVirtualFile virtualFile, @NotNull Document document, @NotNull Project project) { @@ -224,8 +230,8 @@ public final class LanguageConsoleBuilder { return; } - final ConsoleIconGutterComponent lineStartGutter = new ConsoleIconGutterComponent(editor, gutterContentProvider); - final ConsoleGutterComponent lineEndGutter = new ConsoleGutterComponent(editor, gutterContentProvider); + final ConsoleGutterComponent lineStartGutter = new ConsoleGutterComponent(editor, gutterContentProvider, true); + final ConsoleGutterComponent lineEndGutter = new ConsoleGutterComponent(editor, gutterContentProvider, false); JLayeredPane layeredPane = new JBLayeredPane() { @Override public Dimension getPreferredSize() { @@ -245,7 +251,7 @@ public final class LanguageConsoleBuilder { int w = getWidth(); int h = getHeight(); int lineStartGutterWidth = lineStartGutter.getPreferredSize().width; - lineStartGutter.setBounds(0, 0, lineStartGutterWidth, h); + lineStartGutter.setBounds(0, 0, lineStartGutterWidth + gutterContentProvider.getLineStartGutterOverlap(editor.getEditor()), h); editor.setBounds(lineStartGutterWidth, 0, w - lineStartGutterWidth, h); @@ -265,7 +271,7 @@ public final class LanguageConsoleBuilder { } }; - layeredPane.add(lineStartGutter, JLayeredPane.DEFAULT_LAYER); + layeredPane.add(lineStartGutter, JLayeredPane.PALETTE_LAYER); JScrollPane scrollPane = editor.getScrollPane(); layeredPane.add(scrollPane.getViewport().getView(), JLayeredPane.DEFAULT_LAYER); @@ -290,13 +296,13 @@ public final class LanguageConsoleBuilder { } private final class GutterUpdateScheduler extends DocumentAdapter implements DocumentBulkUpdateListener { - private final ConsoleIconGutterComponent lineStartGutter; + private final ConsoleGutterComponent lineStartGutter; private final ConsoleGutterComponent lineEndGutter; private Task gutterSizeUpdater; private RangeHighlighterEx lineSeparatorPainter; - public GutterUpdateScheduler(@NotNull ConsoleIconGutterComponent lineStartGutter, @NotNull ConsoleGutterComponent lineEndGutter) { + public GutterUpdateScheduler(@NotNull ConsoleGutterComponent lineStartGutter, @NotNull ConsoleGutterComponent lineEndGutter) { this.lineStartGutter = lineStartGutter; this.lineEndGutter = lineEndGutter; @@ -393,7 +399,7 @@ public final class LanguageConsoleBuilder { @Override public void run() { if (!getHistoryViewer().isDisposed()) { - lineStartGutter.updateSize(); + lineStartGutter.updateSize(start, end); lineEndGutter.updateSize(start, end); } gutterSizeUpdater = null; diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index da38faf0f8f5..5b88d7c739a3 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.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. @@ -58,10 +58,7 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.testFramework.LightVirtualFile; import com.intellij.ui.JBColor; import com.intellij.ui.SideBorder; -import com.intellij.util.DocumentUtil; -import com.intellij.util.FileContentUtil; -import com.intellij.util.ObjectUtils; -import com.intellij.util.SingleAlarm; +import com.intellij.util.*; import com.intellij.util.ui.AbstractLayoutManager; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -124,6 +121,14 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { } public LanguageConsoleImpl(@NotNull Project project, @NotNull String title, @NotNull LightVirtualFile lightFile, boolean initComponents) { + this(project, title, lightFile, initComponents, null); + } + + LanguageConsoleImpl(@NotNull Project project, + @NotNull String title, + @NotNull LightVirtualFile lightFile, + boolean initComponents, + @Nullable PairFunction<VirtualFile, Project, PsiFile> psiFileFactory) { myProject = project; myTitle = title; myVirtualFile = lightFile; @@ -131,7 +136,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { myHistoryFile = new LightVirtualFile(getTitle() + ".history.txt", FileTypes.PLAIN_TEXT, ""); myEditorDocument = FileDocumentManager.getInstance().getDocument(lightFile); assert myEditorDocument != null; - myFile = createFile(myVirtualFile, myEditorDocument, myProject); + myFile = psiFileFactory == null ? createFile(myVirtualFile, myEditorDocument, myProject) : psiFileFactory.fun(myVirtualFile, myProject); myConsoleEditor = (EditorEx)editorFactory.createEditor(myEditorDocument, myProject); myConsoleEditor.addFocusListener(myFocusListener); myCurrentEditor = myConsoleEditor; @@ -173,7 +178,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { myHistoryViewer.getComponent().addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { - if (myForceScrollToEnd.getAndSet(false)) { + if (myForceScrollToEnd.compareAndSet(true, false)) { scrollHistoryToEnd(); } } @@ -333,6 +338,8 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { } private void setPromptInner(@Nullable final String prompt) { + myUpdateQueue.checkDisposed(); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { @@ -472,20 +479,17 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { public boolean shouldScrollHistoryToEnd() { final Rectangle visibleArea = myHistoryViewer.getScrollingModel().getVisibleArea(); final Dimension contentSize = myHistoryViewer.getContentSize(); - return contentSize.getHeight() - visibleArea.getMaxY() < 2 * myHistoryViewer.getLineHeight(); + return contentSize.getHeight() - visibleArea.getMaxY() < (getMinHistoryLineCount() * myHistoryViewer.getLineHeight()); } private void scrollHistoryToEnd() { - final int lineCount = myHistoryViewer.getDocument().getLineCount(); - if (lineCount == 0) { - return; + if (myHistoryViewer.getDocument().getTextLength() != 0) { + EditorUtil.scrollToTheEnd(myHistoryViewer); } - myHistoryViewer.getCaretModel().moveToOffset(myHistoryViewer.getDocument().getLineStartOffset(lineCount - 1), false); - myHistoryViewer.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); } @NotNull - protected String addTextRangeToHistory(@NotNull TextRange textRange, @NotNull EditorEx consoleEditor, boolean preserveMarkup) { + protected String addTextRangeToHistory(@NotNull TextRange textRange, @NotNull EditorEx inputEditor, boolean preserveMarkup) { doAddPromptToHistory(); final Document history = myHistoryViewer.getDocument(); @@ -493,16 +497,16 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { final int localStartOffset = textRange.getStartOffset(); String text; EditorHighlighter highlighter; - if (consoleEditor instanceof EditorWindow) { - PsiFile file = ((EditorWindow)consoleEditor).getInjectedFile(); + if (inputEditor instanceof EditorWindow) { + PsiFile file = ((EditorWindow)inputEditor).getInjectedFile(); highlighter = HighlighterFactory.createHighlighter(file.getVirtualFile(), EditorColorsManager.getInstance().getGlobalScheme(), getProject()); String fullText = InjectedLanguageUtil.getUnescapedText(file, null, null); highlighter.setText(fullText); text = textRange.substring(fullText); } else { - text = consoleEditor.getDocument().getText(textRange); - highlighter = consoleEditor.getHighlighter(); + text = inputEditor.getDocument().getText(textRange); + highlighter = inputEditor.getHighlighter(); } //offset can be changed after text trimming after insert due to buffer constraints int offset = appendToHistoryDocument(history, text); @@ -524,9 +528,9 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { iterator.advance(); } if (preserveMarkup) { - duplicateHighlighters(markupModel, DocumentMarkupModel.forDocument(consoleEditor.getDocument(), myProject, true), offset, textRange); + duplicateHighlighters(markupModel, DocumentMarkupModel.forDocument(inputEditor.getDocument(), myProject, true), offset, textRange); // don't copy editor markup model, i.e. brace matcher, spell checker, etc. - // duplicateHighlighters(markupModel, consoleEditor.getMarkupModel(), offset, textRange); + // duplicateHighlighters(markupModel, inputEditor.getMarkupModel(), offset, textRange); } if (!text.endsWith("\n")) { appendToHistoryDocument(history, "\n"); @@ -623,7 +627,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { myCurrentEditor = editor; } EmptyAction.registerActionShortcuts(editor.getComponent(), myConsoleEditor.getComponent()); - editor.getCaretModel().addCaretListener(new CaretListener() { + editor.getCaretModel().addCaretListener(new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { queueUiUpdate(false); @@ -686,6 +690,10 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { return true; } + int getMinHistoryLineCount() { + return 2; + } + private class MyLayout extends AbstractLayoutManager { @Override public Dimension preferredLayoutSize(final Container parent) { @@ -700,8 +708,8 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { } final EditorEx history = myHistoryViewer; - final EditorEx editor = componentCount == 2 ? myConsoleEditor : null; - if (editor == null) { + final EditorEx input = componentCount == 2 ? myConsoleEditor : null; + if (input == null) { parent.getComponent(0).setBounds(parent.getBounds()); return; } @@ -711,44 +719,44 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { return; } final Dimension historySize = history.getContentSize(); - final Dimension editorSize = editor.getContentSize(); - final Dimension newEditorSize = new Dimension(); + final Dimension inputSize = input.getContentSize(); + int newInputHeight; // deal with width - final int width = Math.max(editorSize.width, historySize.width); - newEditorSize.width = width + editor.getScrollPane().getHorizontalScrollBar().getHeight(); + final int width = Math.max(inputSize.width, historySize.width); if (isHistoryViewerForceAdditionalColumnsUsage()) { history.getSoftWrapModel().forceAdditionalColumnsUsage(); - editor.getSettings().setAdditionalColumnsCount(2 + (width - editorSize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, editor)); + input.getSettings().setAdditionalColumnsCount(2 + (width - inputSize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, input)); history.getSettings().setAdditionalColumnsCount(2 + (width - historySize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, history)); } - // deal with height - if (historySize.width == 0) { + // deal with height, WEB-11122 we cannot trust editor width — it could be 0 in case of soft wrap even if editor has text + if (history.getDocument().getLineCount() == 0) { historySize.height = 0; } - final int minHistorySize = historySize.height > 0 ? 2 * history.getLineHeight() + (myShowSeparatorLine ? SEPARATOR_THICKNESS : 0) : 0; - final int minEditorSize = editor.isViewer() ? 0 : editor.getLineHeight(); - final int editorPreferred = editor.isViewer() ? 0 : Math.max(minEditorSize, editorSize.height); - final int historyPreferred = Math.max(minHistorySize, historySize.height); - if (panelSize.height < minEditorSize) { - newEditorSize.height = panelSize.height; + + int minHistoryHeight = historySize.height > 0 ? (getMinHistoryLineCount() * history.getLineHeight() + (myShowSeparatorLine ? SEPARATOR_THICKNESS : 0)) : 0; + int minInputHeight = input.isViewer() ? 0 : input.getLineHeight(); + final int inputPreferredHeight = input.isViewer() ? 0 : Math.max(minInputHeight, inputSize.height); + final int historyPreferredHeight = Math.max(minHistoryHeight, historySize.height); + if (panelSize.height < minInputHeight) { + newInputHeight = panelSize.height; } - else if (panelSize.height < editorPreferred) { - newEditorSize.height = panelSize.height - minHistorySize; + else if (panelSize.height < inputPreferredHeight) { + newInputHeight = panelSize.height - minHistoryHeight; } - else if (panelSize.height < editorPreferred + historyPreferred) { - newEditorSize.height = editorPreferred; + else if (panelSize.height < (inputPreferredHeight + historyPreferredHeight) || inputPreferredHeight == 0) { + newInputHeight = inputPreferredHeight; } else { - newEditorSize.height = editorPreferred == 0 ? 0 : panelSize.height - historyPreferred; + newInputHeight = panelSize.height - historyPreferredHeight; } - final Dimension newHistorySize = new Dimension(width, panelSize.height - newEditorSize.height); + int newHistoryHeight = panelSize.height - newInputHeight; // apply - editor.getComponent().setBounds(0, newHistorySize.height, panelSize.width, newEditorSize.height); + input.getComponent().setBounds(0, newHistoryHeight, panelSize.width, newInputHeight); myForceScrollToEnd.compareAndSet(false, shouldScrollHistoryToEnd()); - history.getComponent().setBounds(0, 0, panelSize.width, newHistorySize.height); + history.getComponent().setBounds(0, 0, panelSize.width, newHistoryHeight); } } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index f729219a5389..1c19e6988591 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -386,17 +386,22 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } public void requestScrollingToEnd() { - if (myEditor == null || myFlushAlarm.isDisposed()) return; - final MyFlushRunnable scrollRunnable = new MyFlushRunnable() { + if (myEditor == null || myFlushAlarm.isDisposed()) { + return; + } + + addFlushRequest(new MyFlushRunnable() { @Override public void doRun() { flushDeferredText(); - if (myEditor == null || myFlushAlarm.isDisposed()) return; + if (myEditor == null || myFlushAlarm.isDisposed()) { + return; + } + myEditor.getCaretModel().moveToOffset(myEditor.getDocument().getTextLength()); myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); } - }; - addFlushRequest(scrollRunnable); + }); } private void addFlushRequest(MyFlushRunnable scrollRunnable) { @@ -480,13 +485,12 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo // 'Debugger' tab is active while 'Console' is not). It's also possible that newly added text contains long lines that // are soft wrapped. We want to update viewport position then when the console becomes visible. final Rectangle oldRectangle = e.getOldRectangle(); - final Rectangle newRectangle = e.getNewRectangle(); if (oldRectangle == null) { return; } Editor myEditor = e.getEditor(); - if (oldRectangle.height <= 0 && newRectangle.height > 0 && myEditor.getSoftWrapModel().isSoftWrappingEnabled() + if (oldRectangle.height <= 0 && e.getNewRectangle().height > 0 && myEditor.getSoftWrapModel().isSoftWrappingEnabled() && myEditor.getCaretModel().getOffset() == myEditor.getDocument().getTextLength()) { EditorUtil.scrollToTheEnd(myEditor); } @@ -834,19 +838,14 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo return ApplicationManager.getApplication().runReadAction(new Computable<EditorEx>() { @Override public EditorEx compute() { - final EditorEx editor = createRealEditor(); - + EditorEx editor = createRealEditor(); editor.addEditorMouseListener(new EditorPopupHandler() { @Override public void invokePopup(final EditorMouseEvent event) { popupInvoked(event.getMouseEvent()); } }); - editor.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void beforeDocumentChange(DocumentEvent event) { - } - + editor.getDocument().addDocumentListener(new DocumentAdapter() { @Override public void documentChanged(DocumentEvent event) { onDocumentChanged(event); diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index e54074d08461..5c931bb26a5b 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -34,6 +34,7 @@ import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.actions.IncrementalFindAction; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.event.CaretAdapter; import com.intellij.openapi.editor.event.CaretEvent; import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.editor.ex.DocumentEx; @@ -752,7 +753,7 @@ public class FindUtil { return result; } - private static class MyListener implements CaretListener { + private static class MyListener extends CaretAdapter { private final Editor myEditor; private final RangeHighlighter mySegmentHighlighter; @@ -818,7 +819,7 @@ public class FindUtil { position = HintManager.ABOVE; } } - CaretListener listener = new CaretListener() { + CaretListener listener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { editor.putUserData(KEY, null); diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/TogglePreserveCaseAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/TogglePreserveCaseAction.java index 1ceb62447573..755e2323c57c 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/TogglePreserveCaseAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/TogglePreserveCaseAction.java @@ -1,3 +1,18 @@ +/* + * 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. + * 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.find.editorHeaderActions; import com.intellij.find.EditorSearchComponent; @@ -5,7 +20,7 @@ import com.intellij.find.FindModel; import com.intellij.openapi.actionSystem.AnActionEvent; public class TogglePreserveCaseAction extends EditorHeaderToggleAction implements SecondaryHeaderAction { - private static final String TEXT = "Preser&ve Case"; + private static final String TEXT = "&Preserve Case"; public TogglePreserveCaseAction(EditorSearchComponent editorSearchComponent) { super(editorSearchComponent, TEXT); diff --git a/platform/lang-impl/src/com/intellij/find/findInProject/FindInProjectManager.java b/platform/lang-impl/src/com/intellij/find/findInProject/FindInProjectManager.java index 4c11fe213535..7bc0e0c595f8 100644 --- a/platform/lang-impl/src/com/intellij/find/findInProject/FindInProjectManager.java +++ b/platform/lang-impl/src/com/intellij/find/findInProject/FindInProjectManager.java @@ -127,7 +127,7 @@ public class FindInProjectManager { return processor.process(usage); } }; - FindInProjectUtil.findUsages(findModelCopy, psiDirectory, myProject, true, consumer, processPresentation); + FindInProjectUtil.findUsages(findModelCopy, psiDirectory, myProject, consumer, processPresentation); } finally { myIsFindInProgress = false; diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java new file mode 100644 index 000000000000..3650e188a65e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java @@ -0,0 +1,394 @@ +/* + * 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. + * 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.find.impl; + +import com.intellij.find.FindBundle; +import com.intellij.find.FindModel; +import com.intellij.find.ngrams.TrigramIndex; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectCoreUtil; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.util.text.TrigramBuilder; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileFilter; +import com.intellij.psi.*; +import com.intellij.psi.impl.cache.CacheManager; +import com.intellij.psi.impl.cache.impl.id.IdIndex; +import com.intellij.psi.impl.search.PsiSearchHelperImpl; +import com.intellij.psi.search.*; +import com.intellij.usageView.UsageInfo; +import com.intellij.usages.FindUsagesProcessPresentation; +import com.intellij.usages.UsageLimitUtil; +import com.intellij.usages.impl.UsageViewManagerImpl; +import com.intellij.util.CommonProcessors; +import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; +import gnu.trove.TIntHashSet; +import gnu.trove.TIntIterator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.regex.Pattern; + +/** + * @author peter + */ +class FindInProjectTask { + private static final int FILES_SIZE_LIMIT = 70 * 1024 * 1024; // megabytes. + private static final int SINGLE_FILE_SIZE_LIMIT = 5 * 1024 * 1024; // megabytes. + private final FindModel myFindModel; + private final Project myProject; + private final PsiManager myPsiManager; + @Nullable private final PsiDirectory myPsiDirectory; + private final FileIndex myFileIndex; + private final Condition<VirtualFile> myFileMask; + private final ProgressIndicator myProgress; + @Nullable private final Module myModule; + private final Set<PsiFile> myLargeFiles = ContainerUtil.newTroveSet(); + private boolean myWarningShown; + + FindInProjectTask(@NotNull final FindModel findModel, + @NotNull final Project project, + @Nullable final PsiDirectory psiDirectory) { + myFindModel = findModel; + myProject = project; + myPsiDirectory = psiDirectory; + myPsiManager = PsiManager.getInstance(project); + + final String moduleName = findModel.getModuleName(); + myModule = moduleName == null ? null : ApplicationManager.getApplication().runReadAction(new Computable<Module>() { + @Override + public Module compute() { + return ModuleManager.getInstance(project).findModuleByName(moduleName); + } + }); + myFileIndex = myModule == null ? + ProjectRootManager.getInstance(project).getFileIndex() : + ModuleRootManager.getInstance(myModule).getFileIndex(); + + final String filter = findModel.getFileFilter(); + final Pattern pattern = FindInProjectUtil.createFileMaskRegExp(filter); + + //noinspection unchecked + myFileMask = pattern == null ? Condition.TRUE : new Condition<VirtualFile>() { + @Override + public boolean value(VirtualFile file) { + return file != null && pattern.matcher(file.getName()).matches(); + } + }; + + final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); + myProgress = progress != null ? progress : new EmptyProgressIndicator(); + } + + public void findUsages(@NotNull final Processor<UsageInfo> consumer, @NotNull FindUsagesProcessPresentation processPresentation) { + try { + myProgress.setIndeterminate(true); + myProgress.setText("Scanning indexed files..."); + final Set<PsiFile> filesForFastWordSearch = getFilesForFastWordSearch(); + myProgress.setIndeterminate(false); + + searchInFiles(consumer, processPresentation, filesForFastWordSearch); + + myProgress.setIndeterminate(true); + myProgress.setText("Scanning non-indexed files..."); + final Collection<PsiFile> otherFiles = collectFilesInScope(filesForFastWordSearch); + myProgress.setIndeterminate(false); + + searchInFiles(consumer, processPresentation, otherFiles); + } + catch (ProcessCanceledException e) { + // fine + } + + if (!myLargeFiles.isEmpty()) { + processPresentation.setLargeFilesWereNotScanned(myLargeFiles); + } + + if (!myProgress.isCanceled()) { + myProgress.setText(FindBundle.message("find.progress.search.completed")); + } + } + + private void searchInFiles(Processor<UsageInfo> consumer, FindUsagesProcessPresentation processPresentation, Collection<PsiFile> psiFiles) { + int i = 0; + long totalFilesSize = 0; + int count = 0; + + for (final PsiFile psiFile : psiFiles) { + final VirtualFile virtualFile = psiFile.getVirtualFile(); + final int index = i++; + if (virtualFile == null) continue; + + long fileLength = UsageViewManagerImpl.getFileLength(virtualFile); + if (fileLength == -1) continue; // Binary or invalid + + if (ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile) && !Registry.is("find.search.in.project.files")) continue; + + if (fileLength > SINGLE_FILE_SIZE_LIMIT) { + myLargeFiles.add(psiFile); + continue; + } + + myProgress.checkCanceled(); + myProgress.setFraction((double)index / psiFiles.size()); + String text = FindBundle.message("find.searching.for.string.in.file.progress", + myFindModel.getStringToFind(), virtualFile.getPresentableUrl()); + myProgress.setText(text); + myProgress.setText2(FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count)); + + int countInFile = FindInProjectUtil.processUsagesInFile(psiFile, myFindModel, consumer); + + count += countInFile; + if (countInFile > 0) { + totalFilesSize += fileLength; + if (totalFilesSize > FILES_SIZE_LIMIT && !myWarningShown) { + myWarningShown = true; + String message = FindBundle.message("find.excessive.total.size.prompt", + UsageViewManagerImpl.presentableSize(totalFilesSize), + ApplicationNamesInfo.getInstance().getProductName()); + UsageLimitUtil.showAndCancelIfAborted(myProject, message, processPresentation.getUsageViewPresentation()); + } + } + } + } + + @NotNull + private Collection<PsiFile> collectFilesInScope(@NotNull final Set<PsiFile> alreadySearched) { + SearchScope customScope = myFindModel.getCustomScope(); + final GlobalSearchScope globalCustomScope = toGlobal(customScope); + + final boolean skipIndexed = canRelyOnIndices(); + + class EnumContentIterator implements ContentIterator { + final Set<PsiFile> myFiles = new LinkedHashSet<PsiFile>(); + + @Override + public boolean processFile(@NotNull final VirtualFile virtualFile) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + ProgressManager.checkCanceled(); + if (virtualFile.isDirectory() || !virtualFile.isValid() || + !myFileMask.value(virtualFile) || + (globalCustomScope != null && !globalCustomScope.contains(virtualFile))) { + return; + } + + if (skipIndexed && isCoveredByIdIndex(virtualFile)) { + return; + } + + PsiFile psiFile = myPsiManager.findFile(virtualFile); + if (psiFile != null && !(psiFile instanceof PsiBinaryFile) && !alreadySearched.contains(psiFile)) { + PsiFile sourceFile = (PsiFile)psiFile.getNavigationElement(); + if (sourceFile != null) psiFile = sourceFile; + myFiles.add(psiFile); + } + } + }); + return true; + } + + @NotNull + private Collection<PsiFile> getFiles() { + return myFiles; + } + } + + EnumContentIterator iterator = new EnumContentIterator(); + + if (customScope instanceof LocalSearchScope) { + for (VirtualFile file : getLocalScopeFiles((LocalSearchScope)customScope)) { + iterator.processFile(file); + } + } + else if (myPsiDirectory != null) { + myFileIndex.iterateContentUnderDirectory(myPsiDirectory.getVirtualFile(), iterator); + } + else { + boolean success = myFileIndex.iterateContent(iterator); + if (success && globalCustomScope != null && globalCustomScope.isSearchInLibraries()) { + final VirtualFile[] librarySources = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile[]>() { + @Override + public VirtualFile[] compute() { + OrderEnumerator enumerator = myModule == null ? OrderEnumerator.orderEntries(myProject) : OrderEnumerator.orderEntries(myModule); + return enumerator.withoutModuleSourceEntries().withoutDepModules().getSourceRoots(); + } + }); + iterateAll(librarySources, globalCustomScope, iterator); + } + } + return iterator.getFiles(); + } + + private static boolean isCoveredByIdIndex(VirtualFile file) { + return IdIndex.isIndexable(FileBasedIndexImpl.getFileType(file)) && + ((FileBasedIndexImpl)FileBasedIndex.getInstance()).isIndexingCandidate(file, IdIndex.NAME); + } + + private static boolean iterateAll(@NotNull VirtualFile[] files, @NotNull final GlobalSearchScope searchScope, @NotNull final ContentIterator iterator) { + final FileTypeManager fileTypeManager = FileTypeManager.getInstance(); + final VirtualFileFilter contentFilter = new VirtualFileFilter() { + @Override + public boolean accept(@NotNull final VirtualFile file) { + return file.isDirectory() || + !fileTypeManager.isFileIgnored(file) && !file.getFileType().isBinary() && searchScope.contains(file); + } + }; + for (VirtualFile file : files) { + if (!VfsUtilCore.iterateChildrenRecursively(file, contentFilter, iterator)) return false; + } + return true; + } + + @Nullable + private GlobalSearchScope toGlobal(@Nullable final SearchScope scope) { + if (scope instanceof GlobalSearchScope || scope == null) { + return (GlobalSearchScope)scope; + } + return ApplicationManager.getApplication().runReadAction(new Computable<GlobalSearchScope>() { + @Override + public GlobalSearchScope compute() { + return GlobalSearchScope.filesScope(myProject, getLocalScopeFiles((LocalSearchScope)scope)); + } + }); + } + + @NotNull + private static Set<VirtualFile> getLocalScopeFiles(@NotNull LocalSearchScope scope) { + Set<VirtualFile> files = new LinkedHashSet<VirtualFile>(); + for (PsiElement element : scope.getScope()) { + PsiFile file = element.getContainingFile(); + if (file != null) { + ContainerUtil.addIfNotNull(files, file.getVirtualFile()); + } + } + return files; + } + + private boolean canRelyOnIndices() { + if (DumbService.isDumb(myProject)) return false; + + if (myFindModel.isRegularExpressions()) return false; + + // a local scope may be over a non-indexed file + if (myFindModel.getCustomScope() instanceof LocalSearchScope) return false; + + String text = myFindModel.getStringToFind(); + if (StringUtil.isEmptyOrSpaces(text)) return false; + + if (TrigramIndex.ENABLED) return !TrigramBuilder.buildTrigram(text).isEmpty(); + + // $ is used to separate words when indexing plain-text files but not when indexing + // Java identifiers, so we can't consistently break a string containing $ characters into words + + return myFindModel.isWholeWordsOnly() && text.indexOf('$') < 0; + } + + + @NotNull + private Set<PsiFile> getFilesForFastWordSearch() { + String stringToFind = myFindModel.getStringToFind(); + if (stringToFind.isEmpty() || DumbService.getInstance(myProject).isDumb()) { + return Collections.emptySet(); + } + + SearchScope customScope = myFindModel.getCustomScope(); + GlobalSearchScope scope = myPsiDirectory != null + ? GlobalSearchScopesCore.directoryScope(myPsiDirectory, true) + : myModule != null + ? myModule.getModuleContentScope() + : customScope instanceof GlobalSearchScope + ? (GlobalSearchScope)customScope + : toGlobal(customScope); + if (scope == null) { + scope = ProjectScope.getContentScope(myProject); + } + + final Set<PsiFile> resultFiles = new LinkedHashSet<PsiFile>(); + + if (TrigramIndex.ENABLED) { + Set<Integer> keys = ContainerUtil.newTroveSet(); + TIntHashSet trigrams = TrigramBuilder.buildTrigram(stringToFind); + TIntIterator it = trigrams.iterator(); + while (it.hasNext()) { + keys.add(it.next()); + } + + if (!keys.isEmpty()) { + List<VirtualFile> hits = new ArrayList<VirtualFile>(); + FileBasedIndex.getInstance().getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor<VirtualFile>(hits), scope); + + for (VirtualFile hit : hits) { + if (myFileMask.value(hit)) { + resultFiles.add(findFile(hit)); + } + } + + return resultFiles; + } + } + + PsiSearchHelperImpl helper = (PsiSearchHelperImpl)PsiSearchHelper.SERVICE.getInstance(myProject); + helper.processFilesWithText(scope, UsageSearchContext.ANY, myFindModel.isCaseSensitive(), stringToFind, new Processor<VirtualFile>() { + @Override + public boolean process(VirtualFile file) { + if (myFileMask.value(file)) { + ContainerUtil.addIfNotNull(resultFiles, findFile(file)); + } + return true; + } + }); + + // in case our word splitting is incorrect + for (PsiFile file : CacheManager.SERVICE.getInstance(myProject) + .getFilesWithWord(stringToFind, UsageSearchContext.ANY, scope, myFindModel.isCaseSensitive())) { + if (myFileMask.value(file.getVirtualFile())) { + resultFiles.add(file); + } + } + + return resultFiles; + } + + private PsiFile findFile(@NotNull final VirtualFile virtualFile) { + return ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() { + @Override + public PsiFile compute() { + return myPsiManager.findFile(virtualFile); + } + }); + } + +} diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index 2fefcc9649d4..d788d9c6abe9 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -19,73 +19,54 @@ package com.intellij.find.impl; import com.intellij.BundleBase; import com.intellij.find.*; import com.intellij.find.findInProject.FindInProjectManager; -import com.intellij.find.ngrams.TrigramIndex; import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; -import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.progress.util.TooManyUsagesStatus; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectCoreUtil; -import com.intellij.openapi.roots.*; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Factory; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.util.text.TrigramBuilder; -import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.LocalFileProvider; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; import com.intellij.psi.*; -import com.intellij.psi.impl.cache.CacheManager; -import com.intellij.psi.impl.cache.impl.id.IdIndex; -import com.intellij.psi.search.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.SearchScope; import com.intellij.ui.content.Content; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewManager; import com.intellij.usages.ConfigurableUsageTarget; import com.intellij.usages.FindUsagesProcessPresentation; -import com.intellij.usages.UsageLimitUtil; import com.intellij.usages.UsageViewPresentation; -import com.intellij.usages.impl.UsageViewManagerImpl; -import com.intellij.util.CommonProcessors; import com.intellij.util.Function; import com.intellij.util.PatternUtil; import com.intellij.util.Processor; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.indexing.FileBasedIndexImpl; -import gnu.trove.THashSet; -import gnu.trove.TIntHashSet; -import gnu.trove.TIntIterator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.File; -import java.util.*; +import java.util.List; import java.util.regex.Pattern; public class FindInProjectUtil { private static final int USAGES_PER_READ_ACTION = 100; - private static final int FILES_SIZE_LIMIT = 70 * 1024 * 1024; // megabytes. - private static final int SINGLE_FILE_SIZE_LIMIT = 5 * 1024 * 1024; // megabytes. private FindInProjectUtil() {} @@ -156,34 +137,6 @@ public class FindInProjectUtil { return virtualFile == null ? null : psiManager.findDirectory(virtualFile); } - private static void addFilesUnderDirectory(@NotNull PsiDirectory directory, - @NotNull Collection<PsiFile> fileList, - boolean isRecursive, - @Nullable Pattern fileMaskRegExp) { - final PsiElement[] children = directory.getChildren(); - - for (PsiElement child : children) { - if (child instanceof PsiFile && - (fileMaskRegExp == null || - fileMaskRegExp.matcher(((PsiFile)child).getName()).matches() - ) - ) { - PsiFile file = (PsiFile)child; - PsiFile sourceFile = (PsiFile)file.getNavigationElement(); - if (sourceFile != null) file = sourceFile; - fileList.add(file); - } - else if (isRecursive && child instanceof PsiDirectory) { - addFilesUnderDirectory((PsiDirectory)child, fileList, isRecursive, fileMaskRegExp); - } - } - } - - @Nullable - private static Pattern createFileMaskRegExp(@NotNull FindModel findModel) { - final String filter = findModel.getFileFilter(); - return createFileMaskRegExp(filter); - } @Nullable public static Pattern createFileMaskRegExp(@Nullable String filter) { @@ -210,74 +163,12 @@ public class FindInProjectUtil { public static void findUsages(@NotNull FindModel findModel, final PsiDirectory psiDirectory, @NotNull final Project project, - boolean showWarnings, @NotNull final Processor<UsageInfo> consumer, @NotNull FindUsagesProcessPresentation processPresentation) { - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - - final Collection<PsiFile> psiFiles = getFilesToSearchIn(findModel, project, psiDirectory); - try { - final Set<PsiFile> largeFiles = new THashSet<PsiFile>(); - - int i = 0; - long totalFilesSize = 0; - int count = 0; - final boolean[] warningShown = {false}; - - for (final PsiFile psiFile : psiFiles) { - final VirtualFile virtualFile = psiFile.getVirtualFile(); - final int index = i++; - if (virtualFile == null) continue; - - long fileLength = UsageViewManagerImpl.getFileLength(virtualFile); - if (fileLength == -1) continue; // Binary or invalid - - if (ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile) && !Registry.is("find.search.in.project.files")) continue; - - if (fileLength > SINGLE_FILE_SIZE_LIMIT) { - largeFiles.add(psiFile); - continue; - } - - if (progress != null) { - progress.checkCanceled(); - progress.setFraction((double)index / psiFiles.size()); - String text = FindBundle.message("find.searching.for.string.in.file.progress", - findModel.getStringToFind(), virtualFile.getPresentableUrl()); - progress.setText(text); - progress.setText2(FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count)); - } - - int countInFile = processUsagesInFile(psiFile, findModel, consumer); - - count += countInFile; - if (countInFile > 0) { - totalFilesSize += fileLength; - if (totalFilesSize > FILES_SIZE_LIMIT && !warningShown[0]) { - warningShown[0] = true; - String message = FindBundle.message("find.excessive.total.size.prompt", - UsageViewManagerImpl.presentableSize(totalFilesSize), - ApplicationNamesInfo.getInstance().getProductName()); - UsageLimitUtil.showAndCancelIfAborted(project, message, processPresentation.getUsageViewPresentation()); - } - } - } - - - if (!largeFiles.isEmpty()) { - processPresentation.setLargeFilesWereNotScanned(largeFiles); - } - } - catch (ProcessCanceledException e) { - // fine - } - - if (progress != null && !progress.isCanceled()) { - progress.setText(FindBundle.message("find.progress.search.completed")); - } + new FindInProjectTask(findModel, project, psiDirectory).findUsages(consumer, processPresentation); } - private static int processUsagesInFile(@NotNull final PsiFile psiFile, + static int processUsagesInFile(@NotNull final PsiFile psiFile, @NotNull final FindModel findModel, @NotNull final Processor<UsageInfo> consumer) { if (findModel.getStringToFind().isEmpty()) { @@ -317,279 +208,6 @@ public class FindInProjectUtil { return count; } - private static PsiFile findFile(@NotNull final PsiManager psiManager, @NotNull final VirtualFile virtualFile) { - return ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() { - @Override - public PsiFile compute() { - return psiManager.findFile(virtualFile); - } - }); - } - - @NotNull - private static Collection<PsiFile> getFilesToSearchIn(@NotNull final FindModel findModel, - @NotNull final Project project, - final PsiDirectory psiDirectory) { - final String moduleName = findModel.getModuleName(); - final Module module = moduleName == null ? null : ApplicationManager.getApplication().runReadAction(new Computable<Module>() { - @Override - public Module compute() { - return ModuleManager.getInstance(project).findModuleByName(moduleName); - } - }); - final FileIndex fileIndex = module == null ? - ProjectRootManager.getInstance(project).getFileIndex() : - ModuleRootManager.getInstance(module).getFileIndex(); - - if (psiDirectory == null || findModel.isWithSubdirectories() && fileIndex.isInContent(psiDirectory.getVirtualFile())) { - final Pattern fileMaskRegExp = createFileMaskRegExp(findModel); - // optimization - Pair<Boolean, Collection<PsiFile>> fastWords = getFilesForFastWordSearch(findModel, project, psiDirectory, fileMaskRegExp, module, fileIndex); - final Collection<PsiFile> filesForFastWordSearch = fastWords.getSecond(); - - final boolean useIdIndex = fastWords.getFirst() && canOptimizeForFastWordSearch(findModel); - - SearchScope customScope = findModel.getCustomScope(); - final GlobalSearchScope globalCustomScope = toGlobal(project, customScope); - - class EnumContentIterator implements ContentIterator { - final Set<PsiFile> myFiles = new LinkedHashSet<PsiFile>(filesForFastWordSearch); - final PsiManager psiManager = PsiManager.getInstance(project); - - @Override - public boolean processFile(@NotNull VirtualFile virtualFile) { - ProgressManager.checkCanceled(); - if (virtualFile.isDirectory() || - (fileMaskRegExp != null && !fileMaskRegExp.matcher(virtualFile.getName()).matches()) || - (globalCustomScope != null && !globalCustomScope.contains(virtualFile))) { - return true; - } - - if (useIdIndex && isCoveredByIdIndex(virtualFile)) { - return true; - } - - PsiFile psiFile = findFile(psiManager, virtualFile); - if (psiFile != null && !(psiFile instanceof PsiBinaryFile)) { - myFiles.add(psiFile); - } - return true; - } - - @NotNull - private Collection<PsiFile> getFiles() { - return myFiles; - } - } - - EnumContentIterator iterator = new EnumContentIterator(); - - if (customScope instanceof LocalSearchScope) { - for (VirtualFile file : getLocalScopeFiles((LocalSearchScope)customScope)) { - iterator.processFile(file); - } - } - - if (psiDirectory == null) { - boolean success = fileIndex.iterateContent(iterator); - if (success && globalCustomScope != null && globalCustomScope.isSearchInLibraries()) { - final VirtualFile[] librarySources = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile[]>() { - @Override - public VirtualFile[] compute() { - OrderEnumerator enumerator = module == null ? OrderEnumerator.orderEntries(project) : OrderEnumerator.orderEntries(module); - return enumerator.withoutModuleSourceEntries().withoutDepModules().getSourceRoots(); - } - }); - iterateAll(librarySources, globalCustomScope, iterator); - } - } - else { - fileIndex.iterateContentUnderDirectory(psiDirectory.getVirtualFile(), iterator); - } - return iterator.getFiles(); - } - if (psiDirectory.isValid()) { - final Collection<PsiFile> fileList = new THashSet<PsiFile>(); - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - addFilesUnderDirectory(psiDirectory, fileList, findModel.isWithSubdirectories(), createFileMaskRegExp(findModel)); - } - }); - - return fileList; - } - return Collections.emptyList(); - } - - private static boolean isCoveredByIdIndex(VirtualFile file) { - return IdIndex.isIndexable(FileBasedIndexImpl.getFileType(file)) && - ((FileBasedIndexImpl)FileBasedIndex.getInstance()).isIndexingCandidate(file, IdIndex.NAME); - } - - private static boolean iterateAll(@NotNull VirtualFile[] files, @NotNull final GlobalSearchScope searchScope, @NotNull final ContentIterator iterator) { - final FileTypeManager fileTypeManager = FileTypeManager.getInstance(); - final VirtualFileFilter contentFilter = new VirtualFileFilter() { - @Override - public boolean accept(@NotNull final VirtualFile file) { - return file.isDirectory() || - !fileTypeManager.isFileIgnored(file) && !file.getFileType().isBinary() && searchScope.contains(file); - } - }; - for (VirtualFile file : files) { - if (!VfsUtilCore.iterateChildrenRecursively(file, contentFilter, iterator)) return false; - } - return true; - } - - @Nullable - private static GlobalSearchScope toGlobal(@NotNull final Project project, @Nullable final SearchScope scope) { - if (scope instanceof GlobalSearchScope || scope == null) { - return (GlobalSearchScope)scope; - } - return ApplicationManager.getApplication().runReadAction(new Computable<GlobalSearchScope>() { - @Override - public GlobalSearchScope compute() { - return GlobalSearchScope.filesScope(project, getLocalScopeFiles((LocalSearchScope)scope)); - } - }); - } - - @NotNull - private static Set<VirtualFile> getLocalScopeFiles(@NotNull LocalSearchScope scope) { - Set<VirtualFile> files = new LinkedHashSet<VirtualFile>(); - for (PsiElement element : scope.getScope()) { - PsiFile file = element.getContainingFile(); - if (file != null) { - ContainerUtil.addIfNotNull(files, file.getVirtualFile()); - } - } - return files; - } - - @NotNull - private static Pair<Boolean, Collection<PsiFile>> getFilesForFastWordSearch(@NotNull final FindModel findModel, - @NotNull final Project project, - @Nullable final PsiDirectory psiDirectory, - final Pattern fileMaskRegExp, - @Nullable final Module module, - @NotNull FileIndex fileIndex) { - if (DumbService.getInstance(project).isDumb()) { - return new Pair<Boolean, Collection<PsiFile>>(false, Collections.<PsiFile>emptyList()); - } - - final PsiManager pm = PsiManager.getInstance(project); - CacheManager cacheManager = CacheManager.SERVICE.getInstance(project); - SearchScope customScope = findModel.getCustomScope(); - GlobalSearchScope scope = psiDirectory != null - ? GlobalSearchScopesCore.directoryScope(psiDirectory, true) - : module != null - ? module.getModuleContentScope() - : customScope instanceof GlobalSearchScope - ? (GlobalSearchScope)customScope - : toGlobal(project, customScope); - if (scope == null) { - scope = ProjectScope.getContentScope(project); - } - - Set<Integer> keys = new THashSet<Integer>(30); - final Set<PsiFile> resultFiles = new THashSet<PsiFile>(); - boolean fast = false; - - String stringToFind = findModel.getStringToFind(); - if (TrigramIndex.ENABLED) { - TIntHashSet trigrams = TrigramBuilder.buildTrigram(stringToFind); - TIntIterator it = trigrams.iterator(); - while (it.hasNext()) { - keys.add(it.next()); - } - - if (!keys.isEmpty()) { - fast = true; - List<VirtualFile> hits = new ArrayList<VirtualFile>(); - FileBasedIndex.getInstance().getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor<VirtualFile>(hits), scope); - - for (VirtualFile hit : hits) { - resultFiles.add(findFile(pm, hit)); - } - - filterMaskedFiles(resultFiles, fileMaskRegExp); - if (resultFiles.isEmpty()) return new Pair<Boolean, Collection<PsiFile>>(true, resultFiles); - } - } - - - // $ is used to separate words when indexing plain-text files but not when indexing - // Java identifiers, so we can't consistently break a string containing $ characters into words - - fast |= findModel.isWholeWordsOnly() && stringToFind.indexOf('$') < 0; - - List<String> words = StringUtil.getWordsInStringLongestFirst(stringToFind); - - for (int i = 0; i < words.size(); i++) { - String word = words.get(i); - - PsiFile[] files = cacheManager.getFilesWithWord(word, UsageSearchContext.ANY, scope, findModel.isCaseSensitive()); - if (files.length == 0) { - resultFiles.clear(); - break; - } - - final List<PsiFile> psiFiles = Arrays.asList(files); - - if (i == 0 && keys.isEmpty()) { - resultFiles.addAll(psiFiles); - } - else { - resultFiles.retainAll(psiFiles); - } - - filterMaskedFiles(resultFiles, fileMaskRegExp); - if (resultFiles.isEmpty()) break; - } - - if (stringToFind.isEmpty()) { - fileIndex.iterateContent(new ContentIterator() { - @Override - public boolean processFile(VirtualFile file) { - if (!file.isDirectory() && fileMaskRegExp.matcher(file.getName()).matches()) { - PsiFile psiFile = findFile(pm, file); - if (psiFile != null) { - resultFiles.add(psiFile); - } - } - return true; - } - }); - } - else { - // in case our word splitting is incorrect - PsiFile[] allWordsFiles = - cacheManager.getFilesWithWord(stringToFind, UsageSearchContext.ANY, scope, findModel.isCaseSensitive()); - ContainerUtil.addAll(resultFiles, allWordsFiles); - - filterMaskedFiles(resultFiles, fileMaskRegExp); - } - - return new Pair<Boolean, Collection<PsiFile>>(fast, resultFiles); - } - - private static void filterMaskedFiles(@NotNull final Set<PsiFile> resultFiles, @Nullable final Pattern fileMaskRegExp) { - if (fileMaskRegExp != null) { - for (Iterator<PsiFile> iterator = resultFiles.iterator(); iterator.hasNext();) { - PsiFile file = iterator.next(); - if (!fileMaskRegExp.matcher(file.getName()).matches()) { - iterator.remove(); - } - } - } - } - - private static boolean canOptimizeForFastWordSearch(@NotNull final FindModel findModel) { - return !findModel.isRegularExpressions() - && (findModel.getCustomScope() == null || findModel.getCustomScope() instanceof GlobalSearchScope); - } - private static int addToUsages(@NotNull Document document, @NotNull Processor<UsageInfo> consumer, @NotNull FindModel findModel, @NotNull final PsiFile psiFile, @NotNull int[] offsetRef, int maxUsages) { int count = 0; diff --git a/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java b/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java index 9fdc87e70686..6cf661d2cc6f 100644 --- a/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java +++ b/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.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. @@ -38,13 +38,13 @@ public class TrigramIndex extends ScalarIndexExtension<Integer> { private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return !file.getFileType().isBinary(); } }; private static final FileBasedIndex.InputFilter NO_FILES = new FileBasedIndex.InputFilter() { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return false; } }; @@ -76,11 +76,13 @@ public class TrigramIndex extends ScalarIndexExtension<Integer> { }; } + @NotNull @Override public KeyDescriptor<Integer> getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { if (ENABLED) { diff --git a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java index 86fe9de9b5a8..7e220c149369 100644 --- a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java +++ b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java @@ -569,7 +569,7 @@ public class ReplaceInProjectManager { myIsFindInProgress = true; FindInProjectUtil.findUsages(myFindModelCopy, myPsiDirectory, myProject, - true, new AdapterProcessor<UsageInfo, Usage>(processor, UsageInfo2UsageAdapter.CONVERTER), + new AdapterProcessor<UsageInfo, Usage>(processor, UsageInfo2UsageAdapter.CONVERTER), myProcessPresentation); } finally { diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java index 0985d6b43171..dfd6c9c93548 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.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. @@ -141,7 +141,7 @@ public class DetectedFrameworksData { private static class TIntHashSetExternalizer implements DataExternalizer<TIntHashSet> { @Override - public void save(DataOutput out, TIntHashSet value) throws IOException { + public void save(@NotNull DataOutput out, TIntHashSet value) throws IOException { out.writeInt(value.size()); final TIntIterator iterator = value.iterator(); while (iterator.hasNext()) { @@ -150,7 +150,7 @@ public class DetectedFrameworksData { } @Override - public TIntHashSet read(DataInput in) throws IOException { + public TIntHashSet read(@NotNull DataInput in) throws IOException { int size = in.readInt(); final TIntHashSet set = new TIntHashSet(size); while (size-- > 0) { diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java index bc6eba2bba2c..514f0777a638 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.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. @@ -91,11 +91,13 @@ public class FrameworkDetectionIndex extends ScalarIndexExtension<Integer> { }; } + @NotNull @Override public KeyDescriptor<Integer> getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { final Set<FileType> acceptedTypes = new HashSet<FileType>(); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SaveAsAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SaveAsAction.java index 07eee5583fb8..410eb95e6baa 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SaveAsAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SaveAsAction.java @@ -1,9 +1,9 @@ package com.intellij.ide.actions; +import com.intellij.ide.util.PlatformPackageUtil; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -28,6 +28,6 @@ public class SaveAsAction extends DumbAwareAction { final VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); @SuppressWarnings({"ConstantConditions"}) final PsiElement element = PsiManager.getInstance(project).findFile(virtualFile); if(element==null) return; - CopyHandler.doCopy(new PsiElement[] {element.getContainingFile()}, element.getContainingFile().getContainingDirectory()); + CopyHandler.doCopy(new PsiElement[] {element.getContainingFile()}, PlatformPackageUtil.getDirectory(element)); } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 4dcdfe826e98..a0e5608654b7 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -143,7 +143,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private TitleIndexes myTitleIndexes; private Map<String, String> myConfigurables = new HashMap<String, String>(); - private Alarm myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, ApplicationManager.getApplication()); + private Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, ApplicationManager.getApplication()); private Alarm myUpdateAlarm = new Alarm(ApplicationManager.getApplication()); private JBList myList; private JCheckBox myNonProjectCheckBox; @@ -608,6 +608,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } private void rebuildList(final String pattern) { + assert EventQueue.isDispatchThread() : "Must be EDT"; if (myCalcThread != null && !myCurrentWorker.isProcessed()) { myCurrentWorker = myCalcThread.cancel(); } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index c7a81cbd0cda..f9d4a757f8a7 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -189,7 +189,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo private final SplitterProportionsData splitterProportions = new SplitterProportionsDataImpl(); private final MessageBusConnection myConnection; private final Map<String, Element> myUninitializedPaneState = new HashMap<String, Element>(); - private final Map<String, SelectInTarget> mySelectInTargets = new HashMap<String, SelectInTarget>(); + private final Map<String, SelectInTarget> mySelectInTargets = new LinkedHashMap<String, SelectInTarget>(); private ContentManager myContentManager; private boolean myFoldersAlwaysOnTop = true; diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java b/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java new file mode 100644 index 000000000000..a829cf85594f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java @@ -0,0 +1,149 @@ +/* + * 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. + * 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.ide.scratch; + +import com.intellij.lang.Language; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.ui.ComboboxSpeedSearch; +import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +/** + * @author ignatov + */ +public class CreateScratchFileAction extends AnAction implements DumbAware { + private static final Set<String> FORBIDDEN_LANGUAGES = ContainerUtil.newHashSet("<Generic>", "$XSLT"); + + public CreateScratchFileAction() { + super("Create Scratch File...", "New Scratch File", null); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = e.getProject(); + if (project == null) return; + + MyDialog dialog = new MyDialog(project); + dialog.setResizable(false); + if (dialog.showAndGet()) { + Language language = dialog.getType(); + VirtualFile file = ScratchpadManager.getInstance(project).createScratchFile(language); + if (file == null) return; + OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file); + FileEditorManager.getInstance(project).openTextEditor(descriptor, true); + } + } + + private static class MyDialog extends DialogWrapper { + @Nullable private Project myProject; + @NotNull private JComboBox myComboBox; + + protected MyDialog(@Nullable Project project) { + super(project); + myProject = project; + setTitle("Specify the Language"); + init(); + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + JPanel panel = new JPanel(new BorderLayout()); + myComboBox = createCombo(getLanguages()); + panel.add(myComboBox, BorderLayout.CENTER); + return panel; + } + + @NotNull + public Language getType() { + return ((Language)myComboBox.getSelectedItem()); + } + + @NotNull + private JComboBox createCombo(@NotNull List<Language> languages) { + JComboBox jComboBox = new ComboBox(new CollectionComboBoxModel(languages)); + jComboBox.setRenderer(new ListCellRendererWrapper<Language>() { + @Override + public void customize(JList list, Language lang, int index, boolean selected, boolean hasFocus) { + if (lang != null) { + setText(lang.getDisplayName()); + LanguageFileType associatedLanguage = lang.getAssociatedFileType(); + if (associatedLanguage != null) setIcon(associatedLanguage.getIcon()); + } + } + }); + new ComboboxSpeedSearch(jComboBox) { + @Override + protected String getElementText(Object element) { + return element instanceof Language ? ((Language)element).getDisplayName() : null; + } + }; + Language previous = myProject != null ? ScratchpadManager.getInstance(myProject).getLatestLanguage() : null; + if (previous != null) { + jComboBox.setSelectedItem(previous); + } + + return jComboBox; + } + + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return myComboBox; + } + } + + @NotNull + private static List<Language> getLanguages() { + Set<Language> result = ContainerUtil.newTreeSet(new Comparator<Language>() { + @Override + public int compare(Language l1, Language l2) { + return l1.getDisplayName().compareTo(l2.getDisplayName()); + } + }); + for (Language lang : Language.getRegisteredLanguages()) { + if (!StringUtil.isEmpty(lang.getDisplayName())) result.add(lang); + for (Language dialect : lang.getDialects()) result.add(dialect); + } + return ContainerUtil.filter(result, new Condition<Language>() { + @Override + public boolean value(Language lang) { + String name = lang.getDisplayName(); + return !StringUtil.isEmpty(name) && !FORBIDDEN_LANGUAGES.contains(name); + } + }); + } +}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadFileSystem.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadFileSystem.java new file mode 100644 index 000000000000..e643b625a7b7 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadFileSystem.java @@ -0,0 +1,112 @@ +/* + * 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. + * 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.ide.scratch; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.presentation.Presentation; +import com.intellij.ide.presentation.PresentationProvider; +import com.intellij.lang.Language; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.vfs.VirtualFileSystem; +import com.intellij.openapi.vfs.ex.dummy.DummyFileSystem; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.ui.LayeredIcon; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.List; +import java.util.Map; + +public class ScratchpadFileSystem extends DummyFileSystem { + private static final String PROTOCOL = "scratchpad"; + private final Map<String, VirtualFile> myCachedFiles = ContainerUtil.newHashMap(); + + public static ScratchpadFileSystem getScratchFileSystem() { + return (ScratchpadFileSystem)VirtualFileManager.getInstance().getFileSystem(PROTOCOL); + } + + public void removeByPrefix(@NotNull final String prefix) { + List<String> toRemove = ContainerUtil.findAll(myCachedFiles.keySet(), new Condition<String>() { + @Override + public boolean value(String s) { + return s.startsWith(prefix); + } + }); + for (String s : toRemove) { + myCachedFiles.remove(s); + } + } + + @Override + public VirtualFile findFileByPath(@NotNull String path) { + VirtualFile file = myCachedFiles.get(path); + if (file != null && file.isValid()) return file; + return null; + } + + @NotNull + public VirtualFile addFile(@NotNull String name, @NotNull Language language, @NotNull String prefix) { + VirtualFile file = new MyLightVirtualFile(name, language, prefix); + myCachedFiles.put(file.getPath(), file); + return file; + } + + @NotNull + @Override + public String getProtocol() { + return PROTOCOL; + } + + @NotNull + @Override + public String extractPresentableUrl(@NotNull String path) { + String substring = StringUtil.substringAfter(path, "/"); + return substring != null ? substring : super.extractPresentableUrl(path); + } + + @Presentation(provider = ScratchPresentation.class) + private static class MyLightVirtualFile extends LightVirtualFile { + private final String myPrefix; + + public MyLightVirtualFile(@NotNull String fileName, @NotNull Language language, @NotNull String projectPrefix) { + super(fileName, language, ""); + myPrefix = projectPrefix; + } + + @NotNull + @Override + public VirtualFileSystem getFileSystem() { + return getScratchFileSystem(); + } + + @NotNull + @Override + public String getPath() { + return myPrefix + super.getPath(); + } + } + + public static class ScratchPresentation extends PresentationProvider<MyLightVirtualFile> { + @Override + public Icon getIcon(@NotNull MyLightVirtualFile file) { + return LayeredIcon.create(file.getFileType().getIcon(), AllIcons.Actions.New); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManager.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManager.java new file mode 100644 index 000000000000..53c988ab198f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManager.java @@ -0,0 +1,35 @@ +/* + * 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. + * 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.ide.scratch; + +import com.intellij.lang.Language; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class ScratchpadManager { + public static ScratchpadManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, ScratchpadManager.class); + } + + @NotNull + public abstract VirtualFile createScratchFile(@NotNull Language language); + + @Nullable + public abstract Language getLatestLanguage(); +} diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManagerImpl.java new file mode 100644 index 000000000000..ed931e77f616 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchpadManagerImpl.java @@ -0,0 +1,77 @@ +/* + * 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. + * 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.ide.scratch; + +import com.intellij.lang.Language; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class ScratchpadManagerImpl extends ScratchpadManager implements Disposable { + private final Project myProject; + private final Map<String, Integer> myExtensionsCounterMap = ContainerUtil.newHashMap(); + private Language myLatestLanguage; + + public ScratchpadManagerImpl(@NotNull Project project) { + myProject = project; + } + + @NotNull + @Override + public VirtualFile createScratchFile(@NotNull final Language language) { + myLatestLanguage = language; + return ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() { + @Override + public VirtualFile compute() { + String name = generateFileName(language); + return ScratchpadFileSystem.getScratchFileSystem().addFile(name, language, calculatePrefix(ScratchpadManagerImpl.this.myProject)); + } + }); + } + + @NotNull + private static String calculatePrefix(@NotNull Project project) { + return project.getLocationHash(); + } + + @Override + public Language getLatestLanguage() { + return myLatestLanguage; + } + + @NotNull + private String generateFileName(@NotNull Language language) { + LanguageFileType associatedFileType = language.getAssociatedFileType(); + String ext = associatedFileType != null ? associatedFileType.getDefaultExtension() : "unknown"; + Integer prev = myExtensionsCounterMap.get(ext); + int updated = prev == null ? 1 : ++prev; + myExtensionsCounterMap.put(ext, updated); + String index = updated == 1 ? "" : updated + "."; + return "scratch." + index + ext; + } + + @Override + public void dispose() { + ScratchpadFileSystem.getScratchFileSystem().removeByPrefix(calculatePrefix(myProject)); + } +}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/util/PlatformPackageUtil.java b/platform/lang-impl/src/com/intellij/ide/util/PlatformPackageUtil.java index 01ad4cb38313..30d4933cbcb4 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/PlatformPackageUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/util/PlatformPackageUtil.java @@ -16,7 +16,6 @@ package com.intellij.ide.util; import com.intellij.ide.IdeBundle; -import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; @@ -35,6 +34,7 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.source.resolve.FileContextUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScopes; import com.intellij.util.*; @@ -276,12 +276,10 @@ public class PlatformPackageUtil { } @Nullable - public static PsiDirectory getDirectory(PsiElement element) { - PsiFile file = element.getContainingFile(); - final PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file); - if (context != null) { - file = context.getContainingFile(); - } - return file.getParent(); + public static PsiDirectory getDirectory(@Nullable PsiElement element) { + if (element == null) return null; + // handle injection and fragment editor + PsiFile file = FileContextUtil.getContextFile(element); + return file == null ? null : file.getContainingDirectory(); } } diff --git a/platform/lang-impl/src/com/intellij/injected/editor/CaretModelWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/CaretModelWindow.java index cee529aecccf..33b417de0af7 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/CaretModelWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/CaretModelWindow.java @@ -17,16 +17,18 @@ package com.intellij.injected.editor; import com.intellij.openapi.editor.*; +import com.intellij.openapi.editor.event.CaretAdapter; import com.intellij.openapi.editor.event.CaretEvent; import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.util.Segment; -import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; /** * @author Alexey @@ -102,7 +104,7 @@ public class CaretModelWindow implements CaretModel { private final ListenerWrapperMap<CaretListener> myCaretListeners = new ListenerWrapperMap<CaretListener>(); @Override public void addCaretListener(@NotNull final CaretListener listener) { - CaretListener wrapper = new CaretListener() { + CaretListener wrapper = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { if (!myEditorWindow.getDocument().isValid()) return; // injected document can be destroyed by now @@ -163,6 +165,11 @@ public class CaretModelWindow implements CaretModel { return createInjectedCaret(myDelegate.getPrimaryCaret()); } + @Override + public int getCaretCount() { + return myDelegate.getCaretCount(); + } + @NotNull @Override public List<Caret> getAllCarets() { @@ -204,17 +211,14 @@ public class CaretModelWindow implements CaretModel { } @Override - public void setCaretsAndSelections(@NotNull List<LogicalPosition> caretPositions, @NotNull List<? extends Segment> selections) { - List<LogicalPosition> convertedPositions = new ArrayList<LogicalPosition>(caretPositions); - for (LogicalPosition position : caretPositions) { - convertedPositions.add(myEditorWindow.injectedToHost(position)); - } - List<Segment> convertedSelections = new ArrayList<Segment>(selections.size()); - for (Segment selection : selections) { - convertedSelections.add(new TextRange(myEditorWindow.getDocument().injectedToHost(selection.getStartOffset()), - myEditorWindow.getDocument().injectedToHost(selection.getEndOffset()))); + public void setCaretsAndSelections(@NotNull List<CaretState> caretStates) { + List<CaretState> convertedStates = new ArrayList<CaretState>(caretStates.size()); + for (CaretState state : caretStates) { + convertedStates.add(new CaretState(state.getCaretPosition() == null ? null : myEditorWindow.injectedToHost(state.getCaretPosition()), + state.getSelectionStart() == null ? null : myEditorWindow.injectedToHost(state.getSelectionStart()), + state.getSelectionEnd() == null ? null : myEditorWindow.injectedToHost(state.getSelectionEnd()))); } - myDelegate.setCaretsAndSelections(convertedPositions, convertedSelections); + myDelegate.setCaretsAndSelections(convertedStates); } private InjectedCaret createInjectedCaret(Caret caret) { diff --git a/platform/lang-impl/src/com/intellij/internal/psiView/PsiViewerDialog.java b/platform/lang-impl/src/com/intellij/internal/psiView/PsiViewerDialog.java index 124b5d6ca7b5..dfaa6501831b 100644 --- a/platform/lang-impl/src/com/intellij/internal/psiView/PsiViewerDialog.java +++ b/platform/lang-impl/src/com/intellij/internal/psiView/PsiViewerDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,6 @@ import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataProvider; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -1211,7 +1210,7 @@ public class PsiViewerDialog extends DialogWrapper implements DataProvider, Disp myEditor.setHighlighter(EditorHighlighterFactory.getInstance().createEditorHighlighter(myProject, lightFile)); } - private class EditorListener implements CaretListener, SelectionListener, DocumentListener { + private class EditorListener extends CaretAdapter implements SelectionListener, DocumentListener { @Override public void caretPositionChanged(CaretEvent e) { if (!available() || myEditor.getSelectionModel().hasSelection()) return; diff --git a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java index 9e227b0d8fe0..9e329582ddad 100644 --- a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java +++ b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -165,6 +165,16 @@ public class DiffPreviewPanel implements PreviewPanel { public void caretPositionChanged(CaretEvent e) { select(MergeSearchHelper.findChangeAt(e, getMergePanel(), myIndex)); } + + @Override + public void caretAdded(CaretEvent e) { + + } + + @Override + public void caretRemoved(CaretEvent e) { + + } } @Override diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java new file mode 100644 index 000000000000..81965ba9436d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java @@ -0,0 +1,80 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.actions; + +import com.intellij.find.FindManager; +import com.intellij.find.FindModel; +import com.intellij.find.FindResult; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Caret; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.actionSystem.EditorAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.Nullable; + +public class SelectAllOccurrencesAction extends EditorAction { + protected SelectAllOccurrencesAction() { + super(new Handler()); + } + + private static class Handler extends SelectOccurrencesActionHandler { + @Override + public boolean isEnabled(Editor editor, DataContext dataContext) { + return super.isEnabled(editor, dataContext) && editor.getProject() != null && editor.getCaretModel().supportsMultipleCarets(); + } + + @Override + public void execute(Editor editor, @Nullable Caret c, DataContext dataContext) { + Caret caret = c == null ? editor.getCaretModel().getPrimaryCaret() : c; + + if (!caret.hasSelection()) { + TextRange wordSelectionRange = getSelectionRange(editor, caret); + if (wordSelectionRange != null) { + setSelection(editor, caret, wordSelectionRange); + } + } + + String selectedText = caret.getSelectedText(); + Project project = editor.getProject(); + if (project == null || selectedText == null) { + return; + } + + int caretShiftFromSelectionStart = caret.getOffset() - caret.getSelectionStart(); + FindManager findManager = FindManager.getInstance(project); + + FindModel model = new FindModel(); + model.setStringToFind(selectedText); + model.setCaseSensitive(true); + model.setWholeWordsOnly(true); + + int searchStartOffset = 0; + FindResult findResult = findManager.findString(editor.getDocument().getCharsSequence(), searchStartOffset, model); + while (findResult.isStringFound()) { + int newCaretOffset = caretShiftFromSelectionStart + findResult.getStartOffset(); + EditorActionUtil.makePositionVisible(editor, newCaretOffset); + Caret newCaret = editor.getCaretModel().addCaret(editor.offsetToVisualPosition(newCaretOffset)); + if (newCaret != null) { + setSelection(editor, newCaret, findResult); + } + findResult = findManager.findString(editor.getDocument().getCharsSequence(), findResult.getEndOffset(), model); + } + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java index 81a7851da874..0063a9f3f6e2 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java @@ -15,37 +15,24 @@ */ package com.intellij.openapi.editor.actions; -import com.intellij.codeInsight.editorActions.SelectWordUtil; -import com.intellij.codeInsight.hint.HintManager; -import com.intellij.codeInsight.hint.HintManagerImpl; -import com.intellij.codeInsight.hint.HintUtil; -import com.intellij.find.FindBundle; import com.intellij.find.FindManager; import com.intellij.find.FindModel; import com.intellij.find.FindResult; -import com.intellij.openapi.editor.EditorLastActionTracker; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.editor.actionSystem.EditorAction; -import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; -import com.intellij.ui.LightweightHint; import org.jetbrains.annotations.Nullable; public class SelectNextOccurrenceAction extends EditorAction { - private static final Key<Boolean> NOT_FOUND = Key.create("select.next.occurence.not.found"); - private static final Key<Boolean> WHOLE_WORDS = Key.create("select.next.occurence.whole.words"); - protected SelectNextOccurrenceAction() { super(new Handler()); } - static class Handler extends EditorActionHandler { + static class Handler extends SelectOccurrencesActionHandler { @Override public boolean isEnabled(Editor editor, DataContext dataContext) { return super.isEnabled(editor, dataContext) && editor.getProject() != null && editor.getCaretModel().supportsMultipleCarets(); @@ -54,9 +41,7 @@ public class SelectNextOccurrenceAction extends EditorAction { @Override public void execute(Editor editor, @Nullable Caret c, DataContext dataContext) { Caret caret = c == null ? editor.getCaretModel().getPrimaryCaret() : c; - TextRange wordSelectionRange = SelectWordUtil.getWordSelectionRange(editor.getDocument().getCharsSequence(), - caret.getOffset(), - SelectWordUtil.JAVA_IDENTIFIER_PART_CONDITION); + TextRange wordSelectionRange = getSelectionRange(editor, caret); boolean notFoundPreviously = getAndResetNotFoundStatus(editor); boolean wholeWordSearch = isWholeWordSearch(editor); if (caret.hasSelection()) { @@ -68,7 +53,7 @@ public class SelectNextOccurrenceAction extends EditorAction { FindManager findManager = FindManager.getInstance(project); FindModel model = new FindModel(); - model.setStringToFind(caret.getSelectedText()); + model.setStringToFind(selectedText); model.setCaseSensitive(true); model.setWholeWordsOnly(wholeWordSearch); @@ -102,50 +87,5 @@ public class SelectNextOccurrenceAction extends EditorAction { } editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } - - private static void setSelection(Editor editor, Caret caret, TextRange selectionRange) { - EditorActionUtil.makePositionVisible(editor, selectionRange.getStartOffset()); - EditorActionUtil.makePositionVisible(editor, selectionRange.getEndOffset()); - caret.setSelection(selectionRange.getStartOffset(), selectionRange.getEndOffset()); - } - - - private static void showHint(final Editor editor) { - String message = FindBundle.message("select.next.occurence.not.found.message"); - final LightweightHint hint = new LightweightHint(HintUtil.createInformationLabel(message)); - HintManagerImpl.getInstanceImpl().showEditorHint(hint, - editor, - HintManager.UNDER, - HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, - 0, - false); - } - - static boolean getAndResetNotFoundStatus(Editor editor) { - boolean status = editor.getUserData(NOT_FOUND) != null; - editor.putUserData(NOT_FOUND, null); - return status && isRepeatedActionInvocation(); - } - - private static void setNotFoundStatus(Editor editor) { - editor.putUserData(NOT_FOUND, Boolean.TRUE); - } - - private static boolean isWholeWordSearch(Editor editor) { - if (!isRepeatedActionInvocation()) { - editor.putUserData(WHOLE_WORDS, null); - } - Boolean value = editor.getUserData(WHOLE_WORDS); - return value != null; - } - - private static void setWholeWordSearch(Editor editor, boolean isWholeWordSearch) { - editor.putUserData(WHOLE_WORDS, isWholeWordSearch); - } - - private static boolean isRepeatedActionInvocation() { - String lastActionId = EditorLastActionTracker.getInstance().getLastActionId(); - return IdeActions.ACTION_SELECT_NEXT_OCCURENCE.equals(lastActionId) || IdeActions.ACTION_UNSELECT_LAST_OCCURENCE.equals(lastActionId); - } } } diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java new file mode 100644 index 000000000000..c43eae703fd5 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java @@ -0,0 +1,88 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.actions; + +import com.intellij.codeInsight.editorActions.SelectWordUtil; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.codeInsight.hint.HintManagerImpl; +import com.intellij.codeInsight.hint.HintUtil; +import com.intellij.find.FindBundle; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.editor.Caret; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorLastActionTracker; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.TextRange; +import com.intellij.ui.LightweightHint; +import org.jetbrains.annotations.Nullable; + +abstract public class SelectOccurrencesActionHandler extends EditorActionHandler { + + private static final Key<Boolean> NOT_FOUND = Key.create("select.next.occurence.not.found"); + private static final Key<Boolean> WHOLE_WORDS = Key.create("select.next.occurence.whole.words"); + + protected static void setSelection(Editor editor, Caret caret, TextRange selectionRange) { + EditorActionUtil.makePositionVisible(editor, selectionRange.getStartOffset()); + EditorActionUtil.makePositionVisible(editor, selectionRange.getEndOffset()); + caret.setSelection(selectionRange.getStartOffset(), selectionRange.getEndOffset()); + } + + protected static void showHint(final Editor editor) { + String message = FindBundle.message("select.next.occurence.not.found.message"); + final LightweightHint hint = new LightweightHint(HintUtil.createInformationLabel(message)); + HintManagerImpl.getInstanceImpl().showEditorHint(hint, + editor, + HintManager.UNDER, + HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, + 0, + false); + } + + protected static boolean getAndResetNotFoundStatus(Editor editor) { + boolean status = editor.getUserData(NOT_FOUND) != null; + editor.putUserData(NOT_FOUND, null); + return status && isRepeatedActionInvocation(); + } + + protected static void setNotFoundStatus(Editor editor) { + editor.putUserData(NOT_FOUND, Boolean.TRUE); + } + + protected static boolean isWholeWordSearch(Editor editor) { + if (!isRepeatedActionInvocation()) { + editor.putUserData(WHOLE_WORDS, null); + } + Boolean value = editor.getUserData(WHOLE_WORDS); + return value != null; + } + + @Nullable + protected static TextRange getSelectionRange(Editor editor, Caret caret) { + return SelectWordUtil.getWordSelectionRange(editor.getDocument().getCharsSequence(), + caret.getOffset(), + SelectWordUtil.JAVA_IDENTIFIER_PART_CONDITION); + } + + protected static void setWholeWordSearch(Editor editor, boolean isWholeWordSearch) { + editor.putUserData(WHOLE_WORDS, isWholeWordSearch); + } + + protected static boolean isRepeatedActionInvocation() { + String lastActionId = EditorLastActionTracker.getInstance().getLastActionId(); + return IdeActions.ACTION_SELECT_NEXT_OCCURENCE.equals(lastActionId) || IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE.equals(lastActionId); + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectLastOccurrenceAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectPreviousOccurrenceAction.java index 192e41cdfdb6..489aa4e9fb86 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectLastOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectPreviousOccurrenceAction.java @@ -20,15 +20,14 @@ import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.editor.actionSystem.EditorAction; -import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import org.jetbrains.annotations.Nullable; -public class UnselectLastOccurrenceAction extends EditorAction { - protected UnselectLastOccurrenceAction() { +public class UnselectPreviousOccurrenceAction extends EditorAction { + protected UnselectPreviousOccurrenceAction() { super(new Handler()); } - private static class Handler extends EditorActionHandler { + private static class Handler extends SelectOccurrencesActionHandler { @Override public boolean isEnabled(Editor editor, DataContext dataContext) { return super.isEnabled(editor, dataContext) && editor.getCaretModel().supportsMultipleCarets(); @@ -36,13 +35,13 @@ public class UnselectLastOccurrenceAction extends EditorAction { @Override public void execute(Editor editor, @Nullable Caret caret, DataContext dataContext) { - if (editor.getCaretModel().getAllCarets().size() > 1) { + if (editor.getCaretModel().getCaretCount() > 1) { editor.getCaretModel().removeCaret(editor.getCaretModel().getPrimaryCaret()); } else { editor.getSelectionModel().removeSelection(); } - SelectNextOccurrenceAction.Handler.getAndResetNotFoundStatus(editor); + getAndResetNotFoundStatus(editor); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } } diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java index 4a94d1ad3781..801887614413 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java @@ -33,6 +33,7 @@ import javax.swing.*; public class EnforcedPlainTextFileTypeFactory extends FileTypeFactory { public static final LayeredIcon ENFORCED_PLAIN_TEXT_ICON = new LayeredIcon(2); + public static final String ENFORCED_PLAIN_TEXT = "Enforced Plain Text"; static { ENFORCED_PLAIN_TEXT_ICON.setIcon(AllIcons.FileTypes.Text, 0); @@ -59,13 +60,13 @@ public class EnforcedPlainTextFileTypeFactory extends FileTypeFactory { @NotNull @Override public String getName() { - return "Enforced Plain Text"; + return ENFORCED_PLAIN_TEXT; } @NotNull @Override public String getDescription() { - return "Enforced Plain Text"; + return ENFORCED_PLAIN_TEXT; } @NotNull diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java index 830681b9ba5e..e8a18e423423 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java @@ -26,9 +26,8 @@ import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerListener; import com.intellij.openapi.roots.ex.ProjectRootManagerEx; import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.util.containers.ConcurrentHashMap; import com.intellij.util.indexing.FileBasedIndex; import org.jetbrains.annotations.NotNull; @@ -45,18 +44,21 @@ import java.util.Map; */ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener { private final Map<Project, Collection<VirtualFile>> myPlainTextFileSets = new ConcurrentHashMap<Project, Collection<VirtualFile>>(); - private final Ref<Boolean> mySetsInitialized = new Ref<Boolean>(false); + private volatile boolean mySetsInitialized = false; + private static final Object LOCK = new Object(); public EnforcedPlainTextFileTypeManager() { ProjectManager.getInstance().addProjectManagerListener(this); } public boolean isMarkedAsPlainText(VirtualFile file) { - if (file instanceof StubVirtualFile || file.isDirectory()) return false; - synchronized (mySetsInitialized) { - if (!mySetsInitialized.get()) { - initPlainTextFileSets(); - mySetsInitialized.set(true); + if (!(file instanceof VirtualFileWithId) || file.isDirectory()) return false; + if (!mySetsInitialized) { + synchronized (LOCK) { + if (!mySetsInitialized) { + initPlainTextFileSets(); + mySetsInitialized = true; + } } } for (Project project : myPlainTextFileSets.keySet()) { @@ -74,7 +76,7 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener } public static boolean isApplicableFor(@NotNull VirtualFile file) { - if (file instanceof StubVirtualFile || file.isDirectory()) return false; + if (!(file instanceof VirtualFileWithId) || file.isDirectory()) return false; FileType originalType = FileTypeManager.getInstance().getFileTypeByFileName(file.getName()); return !originalType.isBinary() && originalType != FileTypes.PLAIN_TEXT && originalType != StdFileTypes.JAVA; } @@ -96,7 +98,7 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener fireRootsChanged(filesToSync, isPlainText); } - private static void fireRootsChanged(final Collection<VirtualFile> files, final boolean isAdded) { + private void fireRootsChanged(final Collection<VirtualFile> files, final boolean isAdded) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { @@ -105,6 +107,7 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener ProjectPlainTextFileTypeManager projectPlainTextFileTypeManager = ProjectPlainTextFileTypeManager.getInstance(project); for (VirtualFile file : files) { if (projectPlainTextFileTypeManager.hasProjectContaining(file)) { + ensureProjectFileSetAdded(project, projectPlainTextFileTypeManager); if (isAdded) { projectPlainTextFileTypeManager.addFile(file); } @@ -118,6 +121,13 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener }); } + private void ensureProjectFileSetAdded(@NotNull Project project, + @NotNull ProjectPlainTextFileTypeManager projectPlainTextFileTypeManager) { + if (!myPlainTextFileSets.containsKey(project)) { + myPlainTextFileSets.put(project, projectPlainTextFileTypeManager.getFiles()); + } + } + private static class EnforcedPlainTextFileTypeManagerHolder { private static final EnforcedPlainTextFileTypeManager ourInstance = ServiceManager.getService(EnforcedPlainTextFileTypeManager.class); } diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/PersistentFileSetManager.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/PersistentFileSetManager.java index 6cf91fe5a0c0..67b19d6fa54f 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/PersistentFileSetManager.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/PersistentFileSetManager.java @@ -19,7 +19,7 @@ import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.util.containers.HashSet; import org.jdom.Attribute; import org.jdom.Element; @@ -37,7 +37,7 @@ public class PersistentFileSetManager implements PersistentStateComponent<Elemen private final Set<VirtualFile> myFiles = new HashSet<VirtualFile>(); protected boolean addFile(VirtualFile file) { - if (file instanceof StubVirtualFile || file.isDirectory()) return false; + if (!(file instanceof VirtualFileWithId) || file.isDirectory()) return false; myFiles.add(file); return true; } diff --git a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java index f32a372d11ed..af4484a114d7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java @@ -262,51 +262,61 @@ public class ModuleImpl extends PlatformComponentManagerImpl implements ModuleEx return getStateStore().getOptionValue(optionName); } + @NotNull @Override public GlobalSearchScope getModuleScope() { return myModuleScopeProvider.getModuleScope(); } + @NotNull @Override public GlobalSearchScope getModuleScope(boolean includeTests) { return myModuleScopeProvider.getModuleScope(includeTests); } + @NotNull @Override public GlobalSearchScope getModuleWithLibrariesScope() { return myModuleScopeProvider.getModuleWithLibrariesScope(); } + @NotNull @Override public GlobalSearchScope getModuleWithDependenciesScope() { return myModuleScopeProvider.getModuleWithDependenciesScope(); } + @NotNull @Override public GlobalSearchScope getModuleContentScope() { return myModuleScopeProvider.getModuleContentScope(); } + @NotNull @Override public GlobalSearchScope getModuleContentWithDependenciesScope() { return myModuleScopeProvider.getModuleContentWithDependenciesScope(); } + @NotNull @Override public GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(boolean includeTests) { return myModuleScopeProvider.getModuleWithDependenciesAndLibrariesScope(includeTests); } + @NotNull @Override public GlobalSearchScope getModuleWithDependentsScope() { return myModuleScopeProvider.getModuleWithDependentsScope(); } + @NotNull @Override public GlobalSearchScope getModuleTestsWithDependentsScope() { return myModuleScopeProvider.getModuleTestsWithDependentsScope(); } + @NotNull @Override public GlobalSearchScope getModuleRuntimeScope(boolean includeTests) { return myModuleScopeProvider.getModuleRuntimeScope(includeTests); diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java index cd8c1bf76994..40e1e793a23f 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.checkin; import com.intellij.ide.todo.TodoFilter; import com.intellij.ide.todo.TodoIndexPatternProvider; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.fragments.LineFragment; @@ -302,7 +303,8 @@ public class TodoCheckinHandlerWorker { private static ArrayList<LineFragment> getLineFragments(final String fileName, String beforeContent, String afterContent) throws VcsException { try { - DiffFragment[] woFormattingBlocks = DiffPolicy.LINES_WO_FORMATTING.buildFragments(beforeContent, afterContent); + DiffFragment[] woFormattingBlocks = + DiffPolicy.LINES_WO_FORMATTING.buildFragments(DiffString.create(beforeContent), DiffString.create(afterContent)); DiffFragment[] step1lineFragments = new DiffCorrection.TrueLineBlocks(ComparisonPolicy.IGNORE_SPACE).correctAndNormalize(woFormattingBlocks); return new DiffFragmentsProcessor().process(step1lineFragments); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java index 43bc2facc8a8..bc1254ceca7a 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.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. @@ -108,6 +108,7 @@ public class FileIncludeIndex extends FileBasedIndexExtension<FileIncludeIndex.K }; } + @NotNull @Override public KeyDescriptor<Key> getKeyDescriptor() { return new KeyDescriptor<Key>() { @@ -122,24 +123,25 @@ public class FileIncludeIndex extends FileBasedIndexExtension<FileIncludeIndex.K } @Override - public void save(DataOutput out, Key value) throws IOException { + public void save(@NotNull DataOutput out, Key value) throws IOException { out.writeBoolean(value.isInclude()); value.writeValue(out); } @Override - public Key read(DataInput in) throws IOException { + public Key read(@NotNull DataInput in) throws IOException { boolean isInclude = in.readBoolean(); return isInclude ? IncludeKey.read(in) : new FileKey(in.readInt()); } }; } + @NotNull @Override public DataExternalizer<List<FileIncludeInfoImpl>> getValueExternalizer() { return new DataExternalizer<List<FileIncludeInfoImpl>>() { @Override - public void save(DataOutput out, List<FileIncludeInfoImpl> value) throws IOException { + public void save(@NotNull DataOutput out, List<FileIncludeInfoImpl> value) throws IOException { out.writeInt(value.size()); for (FileIncludeInfoImpl info : value) { out.writeUTF(info.path); @@ -150,7 +152,7 @@ public class FileIncludeIndex extends FileBasedIndexExtension<FileIncludeIndex.K } @Override - public List<FileIncludeInfoImpl> read(DataInput in) throws IOException { + public List<FileIncludeInfoImpl> read(@NotNull DataInput in) throws IOException { int size = in.readInt(); ArrayList<FileIncludeInfoImpl> infos = new ArrayList<FileIncludeInfoImpl>(size); for (int i = 0; i < size; i++) { @@ -161,11 +163,12 @@ public class FileIncludeIndex extends FileBasedIndexExtension<FileIncludeIndex.K }; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new FileBasedIndex.FileTypeSpecificInputFilter() { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { if (file.getFileSystem() == JarFileSystem.getInstance()) { return false; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java index 19f1aa2cd70f..8fa6c5771fdd 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java @@ -55,6 +55,7 @@ import com.intellij.psi.injection.ReferenceInjector; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.SmartList; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -214,16 +215,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT Language forcedLanguage = myContextElement.getUserData(InjectedFileViewProvider.LANGUAGE_FOR_INJECTED_COPY_KEY); myLanguage = forcedLanguage == null ? LanguageSubstitutors.INSTANCE.substituteLanguage(myLanguage, virtualFile, myProject) : forcedLanguage; - DocumentImpl decodedDocument; - if (StringUtil.indexOf(outChars, '\r') == -1) { - decodedDocument = new DocumentImpl(outChars); - } - else { - decodedDocument = new DocumentImpl("", true); - decodedDocument.setAcceptSlashR(true); - decodedDocument.replaceString(0,0,outChars); - } - FileDocumentManagerImpl.registerDocument(decodedDocument, virtualFile); + createDocument(virtualFile); InjectedFileViewProvider viewProvider = new InjectedFileViewProvider(myPsiManager, virtualFile, documentWindow, myLanguage); ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(myLanguage); @@ -307,6 +299,14 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT } } + @NotNull + private static DocumentEx createDocument(@NotNull LightVirtualFile virtualFile) { + CharSequence content = virtualFile.getContent(); + DocumentImpl document = new DocumentImpl(content, StringUtil.indexOf(content, '\r') >= 0, false); + FileDocumentManagerImpl.registerDocument(document, virtualFile); + return document; + } + // returns true if shreds were set, false if old ones were reused private static boolean cacheEverything(@NotNull Place place, @NotNull DocumentWindowImpl documentWindow, diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java index 0877a65f51bc..6682da34ed4c 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.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. @@ -19,6 +19,7 @@ */ package com.intellij.psi.stubs; +import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.*; @@ -26,12 +27,16 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.NotNullComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; +import com.intellij.psi.LanguageSubstitutors; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -53,7 +58,6 @@ import org.jetbrains.annotations.Nullable; import java.io.*; import java.util.*; -import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; @@ -161,7 +165,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe private static class StubIdExternalizer implements DataExternalizer<StubIdList> { @Override - public void save(final DataOutput out, @NotNull final StubIdList value) throws IOException { + public void save(@NotNull final DataOutput out, @NotNull final StubIdList value) throws IOException { int size = value.size(); if (size == 0) { DataInputOutputUtil.writeINT(out, Integer.MAX_VALUE); @@ -179,7 +183,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe @NotNull @Override - public StubIdList read(final DataInput in) throws IOException { + public StubIdList read(@NotNull final DataInput in) throws IOException { int size = DataInputOutputUtil.readINT(in); if (size == Integer.MAX_VALUE) { return new StubIdList(); @@ -424,9 +428,10 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe public <K> void updateIndex(@NotNull StubIndexKey key, int fileId, @NotNull final Map<K, StubIdList> oldValues, @NotNull Map<K, StubIdList> newValues) { try { final MyIndex<K> index = (MyIndex<K>)myIndices.get(key); - index.updateWithMap(fileId, newValues, new Callable<Collection<K>>() { + index.updateWithMap(fileId, newValues, new NotNullComputable<Collection<K>>() { + @NotNull @Override - public Collection<K> call() throws Exception { + public Collection<K> compute() { return oldValues.keySet(); } }); @@ -445,7 +450,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe @Override public void updateWithMap(final int inputId, @NotNull final Map<K, StubIdList> newData, - @NotNull Callable<Collection<K>> oldKeysGetter) throws StorageException { + @NotNull NotNullComputable<Collection<K>> oldKeysGetter) throws StorageException { super.updateWithMap(inputId, newData, oldKeysGetter); } } @@ -465,8 +470,13 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe out.printf("\nfile: %s\npsiElement: %s\nrequiredClass: %s\nactualClass: %s", file, psi, requiredClass, psi.getClass()); - out.printf("\nvirtualFile: size:%s; stamp:%s; modCount:%s", - file.getLength(), file.getModificationStamp(), file.getModificationCount()); + FileType fileType = file.getFileType(); + Language language = fileType instanceof LanguageFileType ? + LanguageSubstitutors.INSTANCE.substituteLanguage(((LanguageFileType)fileType).getLanguage(), file, psi.getProject()) : + Language.ANY; + out.printf("\nvirtualFile: size:%s; stamp:%s; modCount:%s; fileType:%s; language:%s", + file.getLength(), file.getModificationStamp(), file.getModificationCount(), + fileType.getName(), language.getID()); Document document = FileDocumentManager.getInstance().getCachedDocument(file); if (document != null) { @@ -478,8 +488,9 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe PsiFile psiFile = psi.getManager().findFile(file); if (psiFile != null) { - out.printf("\npsiFile: size:%s; stamp:%s; class:%s", - psiFile.getTextLength(), psiFile.getViewProvider().getModificationStamp(), psiFile.getClass().getName()); + out.printf("\npsiFile: size:%s; stamp:%s; class:%s; language:%s", + psiFile.getTextLength(), psiFile.getViewProvider().getModificationStamp(), psiFile.getClass().getName(), + psiFile.getLanguage().getID()); } StubTree stub = psiFile instanceof PsiFileWithStubSupport ? ((PsiFileWithStubSupport)psiFile).getStubTree() : null; diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 93e2b3541f41..4cb07a623f03 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.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. @@ -23,6 +23,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.util.NotNullComputable; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.FileAttribute; @@ -37,7 +38,6 @@ import org.jetbrains.annotations.NotNull; import java.io.*; import java.util.*; -import java.util.concurrent.Callable; /* * @author max @@ -54,13 +54,13 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi private static final DataExternalizer<SerializedStubTree> KEY_EXTERNALIZER = new DataExternalizer<SerializedStubTree>() { @Override - public void save(final DataOutput out, @NotNull final SerializedStubTree v) throws IOException { + public void save(@NotNull final DataOutput out, @NotNull final SerializedStubTree v) throws IOException { v.write(out); } @NotNull @Override - public SerializedStubTree read(final DataInput in) throws IOException { + public SerializedStubTree read(@NotNull final DataInput in) throws IOException { return new SerializedStubTree(in); } }; @@ -226,11 +226,11 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi @NotNull @Override - public UpdatableIndex<Integer, SerializedStubTree, FileContent> createIndexImplementation(final ID<Integer, SerializedStubTree> indexId, @NotNull final FileBasedIndex owner, @NotNull IndexStorage<Integer, SerializedStubTree> storage) + public UpdatableIndex<Integer, SerializedStubTree, FileContent> createIndexImplementation(@NotNull final ID<Integer, SerializedStubTree> indexId, @NotNull final FileBasedIndex owner, @NotNull IndexStorage<Integer, SerializedStubTree> storage) throws StorageException { if (storage instanceof MemoryIndexStorage) { final MemoryIndexStorage<Integer, SerializedStubTree> memStorage = (MemoryIndexStorage<Integer, SerializedStubTree>)storage; - memStorage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { + memStorage.addBufferingStateListener(new MemoryIndexStorage.BufferingStateListener() { @Override public void bufferingStateChanged(final boolean newState) { ((StubIndexImpl)StubIndex.getInstance()).setDataBufferingEnabled(newState); @@ -294,7 +294,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi @Override protected void updateWithMap(final int inputId, @NotNull final Map<Integer, SerializedStubTree> newData, - @NotNull Callable<Collection<Integer>> oldKeysGetter) + @NotNull NotNullComputable<Collection<Integer>> oldKeysGetter) throws StorageException { checkNameStorage(); diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index 773bb2b54ef6..2532a9207298 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -465,7 +465,7 @@ public abstract class BaseRefactoringProcessor implements Runnable { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); RefactoringListenerManagerImpl listenerManager = (RefactoringListenerManagerImpl)RefactoringListenerManager.getInstance(myProject); myTransaction = listenerManager.startTransaction(); - final Map<RefactoringHelper, Object> preparedData = new HashMap<RefactoringHelper, Object>(); + final Map<RefactoringHelper, Object> preparedData = new LinkedHashMap<RefactoringHelper, Object>(); final Runnable prepareHelpersRunnable = new Runnable() { @Override public void run() { diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MethodSignatureEditor.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MethodSignatureEditor.java index 83122e1cc00b..d5d4812d93da 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MethodSignatureEditor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MethodSignatureEditor.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. @@ -21,10 +21,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.LogicalPosition; -import com.intellij.openapi.editor.event.CaretEvent; -import com.intellij.openapi.editor.event.CaretListener; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.impl.CaretModelImpl; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.util.Key; @@ -163,7 +160,7 @@ public abstract class MethodSignatureEditor<M extends PsiElement> extends Editor CodeStyleManager.getInstance(getProject()).reformatText(myFile, range.getStartOffset(), range.getEndOffset()); } }); - editor.getCaretModel().addCaretListener(new CaretListener() { + editor.getCaretModel().addCaretListener(new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { createFromString(); diff --git a/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesDialog.java b/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesDialog.java index 1a0882add180..5314b49dcf16 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesDialog.java +++ b/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesDialog.java @@ -101,7 +101,9 @@ public class CopyFilesOrDirectoriesDialog extends DialogWrapper { PsiFile file = (PsiFile)elements[0]; String url = shortenPath(file.getVirtualFile()); text = RefactoringBundle.message(doClone ? "copy.files.clone.file.0" : "copy.files.copy.file.0", url); - final String fileName = file.getName(); + // keep extensions (dots) and spaces, e.g. fragment file name will be "HTML Fragment (my.sql_61).html" + // and leave ordinary file name AS IS + String fileName = PathUtil.suggestFileName(file.getName(), true, true); myNewNameField.setText(fileName); final int dotIdx = fileName.lastIndexOf("."); if (dotIdx > -1) { diff --git a/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java b/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java index fa80f335c996..fcbc320a320f 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java @@ -18,6 +18,7 @@ package com.intellij.refactoring.copy; import com.intellij.CommonBundle; import com.intellij.ide.CopyPasteDelegator; import com.intellij.ide.util.EditorHelper; +import com.intellij.ide.util.PlatformPackageUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.project.Project; @@ -119,11 +120,11 @@ public class CopyFilesOrDirectoriesHandler extends CopyHandlerDelegateBase { PsiDirectory targetDirectory; if (element instanceof PsiDirectory) { targetDirectory = ((PsiDirectory)element).getParentDirectory(); - assert targetDirectory != null : element; } else { - targetDirectory = ((PsiFile)element).getContainingDirectory(); + targetDirectory = PlatformPackageUtil.getDirectory(element); } + assert targetDirectory != null : element; PsiElement[] elements = {element}; CopyFilesOrDirectoriesDialog dialog = new CopyFilesOrDirectoriesDialog(elements, null, element.getProject(), true); @@ -146,7 +147,7 @@ public class CopyFilesOrDirectoriesHandler extends CopyHandlerDelegateBase { directory = directory.getParentDirectory(); } else if (element instanceof PsiFile) { - directory = ((PsiFile)element).getContainingDirectory(); + directory = PlatformPackageUtil.getDirectory(element); } else { throw new IllegalArgumentException("unexpected element " + element); diff --git a/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java b/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java index 76939d421741..0ff4c62461b5 100644 --- a/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java @@ -127,8 +127,6 @@ public class DetailViewImpl extends JPanel implements DetailView, UserDataHolder @Override public void navigateInPreviewEditor(PreviewEditorState editorState) { - myEditorState = editorState; - final VirtualFile file = editorState.getFile(); final LogicalPosition positionToNavigate = editorState.getNavigate(); final TextAttributes lineAttributes = editorState.getAttributes(); @@ -136,6 +134,7 @@ public class DetailViewImpl extends JPanel implements DetailView, UserDataHolder Project project = myProject; clearEditor(); + myEditorState = editorState; remove(myLabel); if (document != null) { if (getEditor() == null || getEditor().getDocument() != document) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java index 50e87f85baab..34b7937cb7a1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.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. @@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable; */ public interface AbstractIndex<Key, Value> { @NotNull - ValueContainer<Value> getData(Key key) throws StorageException; + ValueContainer<Value> getData(@NotNull Key key) throws StorageException; - boolean processAllKeys(Processor<Key> processor, GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; + boolean processAllKeys(@NotNull Processor<Key> processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java index 1648f878066c..f888981f21d4 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.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. @@ -19,6 +19,7 @@ package com.intellij.util.indexing; import com.intellij.openapi.util.Computable; import gnu.trove.TIntHashSet; import gnu.trove.TIntProcedure; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Iterator; @@ -72,11 +73,13 @@ class ChangeTrackingValueContainer<Value> extends UpdatableValueContainer<Value> return getMergedData().size(); } + @NotNull @Override public Iterator<Value> getValueIterator() { return getMergedData().getValueIterator(); } + @NotNull @Override public List<Value> toValueList() { return getMergedData().toValueList(); @@ -87,11 +90,13 @@ class ChangeTrackingValueContainer<Value> extends UpdatableValueContainer<Value> return getMergedData().isAssociated(value, inputId); } + @NotNull @Override public IntPredicate getValueAssociationPredicate(Value value) { return getMergedData().getValueAssociationPredicate(value); } + @NotNull @Override public IntIterator getInputIdsIterator(final Value value) { return getMergedData().getInputIdsIterator(value); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/CustomImplementationFileBasedIndexExtension.java b/platform/lang-impl/src/com/intellij/util/indexing/CustomImplementationFileBasedIndexExtension.java index 32b22274dced..d504daf8e808 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/CustomImplementationFileBasedIndexExtension.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/CustomImplementationFileBasedIndexExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,6 @@ import org.jetbrains.annotations.NotNull; public abstract class CustomImplementationFileBasedIndexExtension<K, V, I> extends FileBasedIndexExtension<K, V> { @NotNull - public abstract UpdatableIndex<K, V, I> createIndexImplementation(final ID<K, V> indexId, @NotNull FileBasedIndex owner, @NotNull IndexStorage<K, V> storage) + public abstract UpdatableIndex<K, V, I> createIndexImplementation(@NotNull ID<K, V> indexId, @NotNull FileBasedIndex owner, @NotNull IndexStorage<K, V> storage) throws StorageException; }
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index ed0dd1b19c6b..578529352033 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -252,8 +252,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { myConnection = connection; } - public static boolean isProjectOrWorkspaceFile(final VirtualFile file, - final @Nullable FileType fileType) { + public static boolean isProjectOrWorkspaceFile(@NotNull VirtualFile file, + @Nullable FileType fileType) { if (fileType instanceof InternalFileType) return true; VirtualFile parent = file.isDirectory() ? file: file.getParent(); while(parent instanceof VirtualFileSystemEntry) { @@ -369,8 +369,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { } /** - * @param extension - * @param isCurrentVersionCorrupted * @return true if registered index requires full rebuild for some reason, e.g. is just created or corrupted */ private <K, V> boolean registerIndexer(@NotNull final FileBasedIndexExtension<K, V> extension, final boolean isCurrentVersionCorrupted) @@ -394,7 +392,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { return versionChanged; } - private <K, V> void initIndexStorage(final FileBasedIndexExtension<K, V> extension, int version, File versionFile) + private <K, V> void initIndexStorage(@NotNull FileBasedIndexExtension<K, V> extension, int version, @NotNull File versionFile) throws IOException { MapIndexStorage<K, V> storage = null; final ID<K, V> name = extension.getName(); @@ -429,7 +427,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { ids.add(name); } }); - } else { + } + else { myIndicesWithoutFileTypeInfo.add(name); } @@ -545,12 +544,12 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull MemoryIndexStorage<K, ?> storage) throws IOException { final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); - final Ref<Boolean> isBufferingMode = new Ref<Boolean>(false); + final AtomicBoolean isBufferingMode = new AtomicBoolean(); final TIntObjectHashMap<Collection<K>> tempMap = new TIntObjectHashMap<Collection<K>>(); final DataExternalizer<Collection<K>> dataExternalizer = new DataExternalizer<Collection<K>>() { @Override - public void save(DataOutput out, @NotNull Collection<K> value) throws IOException { + public void save(@NotNull DataOutput out, @NotNull Collection<K> value) throws IOException { try { DataInputOutputUtil.writeINT(out, value.size()); for (K key : value) { @@ -564,7 +563,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull @Override - public Collection<K> read(DataInput in) throws IOException { + public Collection<K> read(@NotNull DataInput in) throws IOException { try { final int size = DataInputOutputUtil.readINT(in); final List<K> list = new ArrayList<K>(size); @@ -621,7 +620,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { } }; - storage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { + storage.addBufferingStateListener(new MemoryIndexStorage.BufferingStateListener() { @Override public void bufferingStateChanged(boolean newState) { synchronized (map) { @@ -715,10 +714,11 @@ public class FileBasedIndexImpl extends FileBasedIndex { } @Override - public <K> boolean processAllKeys(@NotNull final ID<K, ?> indexId, Processor<K> processor, @Nullable Project project) { - return processAllKeys(indexId, processor, project != null ? GlobalSearchScope.allScope(project) : new EverythingGlobalScope(), null); + public <K> boolean processAllKeys(@NotNull final ID<K, ?> indexId, @NotNull Processor<K> processor, @Nullable Project project) { + return processAllKeys(indexId, processor, project == null ? new EverythingGlobalScope() : GlobalSearchScope.allScope(project), null); } + @Override public <K> boolean processAllKeys(@NotNull ID<K, ?> indexId, @NotNull Processor<K> processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) { try { final UpdatableIndex<K, ?, FileContent> index = getIndex(indexId); @@ -949,7 +949,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { return null; } - private <K, V> boolean processValuesImpl(@NotNull final ID<K, V> indexId, final K dataKey, final boolean ensureValueProcessedOnce, + private <K, V> boolean processValuesImpl(@NotNull final ID<K, V> indexId, @NotNull final K dataKey, final boolean ensureValueProcessedOnce, @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor<V> processor, @NotNull final GlobalSearchScope scope, @Nullable final IdFilter idFilter) { ThrowableConvertor<UpdatableIndex<K, V, FileContent>, Boolean, StorageException> keyProcessor = @@ -1058,6 +1058,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { }); } + @Override public boolean containsFileId(int id) { if (id < myMinId) return false; if (id > myMaxId) return false; @@ -1659,7 +1660,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { return (UpdatableIndex<K, V, FileContent>)pair.getFirst(); } - private InputFilter getInputFilter(ID<?, ?> indexId) { + private InputFilter getInputFilter(@NotNull ID<?, ?> indexId) { final Pair<UpdatableIndex<?, ?, FileContent>, InputFilter> pair = myIndices.get(indexId); assert pair != null : "Index data is absent for index " + indexId; @@ -1766,7 +1767,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - public static FileType getFileType(VirtualFile file) { + @NotNull + public static FileType getFileType(@NotNull VirtualFile file) { FileType fileType = file.getFileType(); if (fileType == FileTypes.PLAIN_TEXT && FileTypeManagerImpl.isFileTypeDetectedFromContent(file)) { fileType = FileTypes.UNKNOWN; @@ -1803,7 +1805,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { fc.putUserData(IndexingDataKeys.PROJECT, project); } - private void updateSingleIndex(final ID<?, ?> indexId, @NotNull final VirtualFile file, @Nullable FileContent currentFC) + private void updateSingleIndex(@NotNull ID<?, ?> indexId, @NotNull final VirtualFile file, @Nullable FileContent currentFC) throws StorageException { if (ourRebuildStatus.get(indexId).get() == REQUIRES_REBUILD) { return; // the index is scheduled for rebuild, no need to update @@ -1823,8 +1825,9 @@ public class FileBasedIndexImpl extends FileBasedIndex { ); } - private Runnable createIndexedStampUpdateRunnable(final ID<?, ?> indexId, - final VirtualFile file, + @NotNull + private Runnable createIndexedStampUpdateRunnable(@NotNull final ID<?, ?> indexId, + @NotNull final VirtualFile file, final boolean hasContent) { return new Runnable() { @Override @@ -1843,7 +1846,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { }; } - private Computable<Boolean> createUpdateComputableWithBufferingDisabled(final Computable<Boolean> update) { + @NotNull + private Computable<Boolean> createUpdateComputableWithBufferingDisabled(@NotNull final Computable<Boolean> update) { return new Computable<Boolean>() { @Override public Boolean compute() { @@ -2080,7 +2084,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { }); } - private void invalidateIndicesForFile(final VirtualFile file, boolean markForReindex) { + private void invalidateIndicesForFile(@NotNull final VirtualFile file, boolean markForReindex) { cleanProcessedFlag(file); IndexingStamp.flushCache(file); @@ -2439,12 +2443,12 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - private boolean shouldIndexFile(final VirtualFile file, final ID<?, ?> indexId) { + private boolean shouldIndexFile(@NotNull VirtualFile file, @NotNull ID<?, ?> indexId) { return getInputFilter(indexId).acceptInput(file) && (isMock(file) || !isFileIndexed(file, indexId)); } - private static boolean isFileIndexed(VirtualFile file, ID<?, ?> indexId) { + private static boolean isFileIndexed(VirtualFile file, @NotNull ID<?, ?> indexId) { return IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId)); } @@ -2537,7 +2541,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { } @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return file instanceof VirtualFileWithId && myDelegate.acceptInput(file); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java index 78814029780c..110db7255f84 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -119,14 +119,15 @@ public class FileBasedIndexProjectHandler extends AbstractProjectComponent imple return myIndex.getNumberOfPendingInvalidations(); } + @NotNull @Override - public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { + public VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator) { Collection<VirtualFile> files = myIndex.getFilesToUpdate(myProject); return VfsUtilCore.toVirtualFileArray(files); } @Override - public void processFile(FileContent fileContent) { + public void processFile(@NotNull FileContent fileContent) { myIndex.processRefreshedFile(myProject, fileContent); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexInfrastructure.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexInfrastructure.java index 6d168332e8c5..226542e49366 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexInfrastructure.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexInfrastructure.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. @@ -47,23 +47,28 @@ public class IndexInfrastructure { private IndexInfrastructure() { } + @NotNull public static File getVersionFile(@NotNull ID<?, ?> indexName) { return new File(getIndexDirectory(indexName, true), indexName + ".ver"); } + @NotNull public static File getStorageFile(@NotNull ID<?, ?> indexName) { return new File(getIndexRootDir(indexName), indexName.toString()); } + @NotNull public static File getInputIndexStorageFile(@NotNull ID<?, ?> indexName) { - return new File(getIndexRootDir(indexName), indexName.toString()+"_inputs"); + return new File(getIndexRootDir(indexName), indexName +"_inputs"); } + @NotNull public static File getIndexRootDir(@NotNull ID<?, ?> indexName) { return getIndexDirectory(indexName, false); } - private static File getIndexDirectory(ID<?, ?> indexName, boolean forVersion) { + @NotNull + private static File getIndexDirectory(@NotNull ID<?, ?> indexName, boolean forVersion) { final String dirName = indexName.toString().toLowerCase(Locale.US); // store StubIndices under StubUpdating index' root to ensure they are deleted // when StubUpdatingIndex version is changed @@ -76,7 +81,7 @@ public class IndexInfrastructure { private static volatile long ourLastStamp; // ensure any file index stamp increases - public static synchronized void rewriteVersion(final File file, final int version) throws IOException { + public static synchronized void rewriteVersion(@NotNull final File file, final int version) throws IOException { final long prevLastModifiedValue = file.lastModified(); if (file.exists()) { FileUtil.delete(file); @@ -108,7 +113,7 @@ public class IndexInfrastructure { } } - public static long getIndexCreationStamp(ID<?, ?> indexName) { + public static long getIndexCreationStamp(@NotNull ID<?, ?> indexName) { Long version = ourIndexIdToCreationStamp.get(indexName); if (version != null) return version.longValue(); @@ -118,7 +123,7 @@ public class IndexInfrastructure { return stamp; } - public static boolean versionDiffers(final File versionFile, final int currentIndexVersion) { + public static boolean versionDiffers(@NotNull File versionFile, final int currentIndexVersion) { try { ourLastStamp = Math.max(ourLastStamp, versionFile.lastModified()); final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(versionFile))); @@ -137,7 +142,7 @@ public class IndexInfrastructure { } @Nullable - public static VirtualFile findFileById(final PersistentFS fs, final int id) { + public static VirtualFile findFileById(@NotNull PersistentFS fs, final int id) { if (ourUnitTestMode) { final VirtualFile testFile = findTestFile(id); if (testFile != null) { @@ -159,7 +164,7 @@ public class IndexInfrastructure { } @Nullable - public static VirtualFile findFileByIdIfCached(final PersistentFS fs, final int id) { + public static VirtualFile findFileByIdIfCached(@NotNull PersistentFS fs, final int id) { if (ourUnitTestMode) { final VirtualFile testFile = findTestFile(id); if (testFile != null) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java index 0f8bb67f00fc..1020876ca2e4 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,15 +33,16 @@ public interface IndexStorage<Key, Value> extends Flushable { void addValue(Key key, int inputId, Value value) throws StorageException; - void removeAllValues(Key key, int inputId) throws StorageException; + void removeAllValues(@NotNull Key key, int inputId) throws StorageException; void clear() throws StorageException; @NotNull ValueContainer<Value> read(Key key) throws StorageException; - boolean processKeys(Processor<Key> processor, GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; + boolean processKeys(@NotNull Processor<Key> processor, GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; + @NotNull Collection<Key> getKeys() throws StorageException; void close() throws StorageException; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java index ebf6906a0d1c..79a7cb684486 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.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. @@ -26,14 +26,19 @@ import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.TObjectLongHashMap; import gnu.trove.TObjectLongProcedure; import gnu.trove.TObjectProcedure; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentMap; /** * @author Eugene Zhuravlev @@ -100,16 +105,17 @@ public class IndexingStamp { } } }); - } else { + } + else { DataInputOutputUtil.writeTIME(stream, DataInputOutputUtil.timeBase); } } - public long get(ID<?, ?> id) { + private long get(ID<?, ?> id) { return myIndexStamps != null? myIndexStamps.get(id) : 0L; } - public void set(ID<?, ?> id, long tmst) { + private void set(ID<?, ?> id, long tmst) { try { if (tmst < 0) { if (myIndexStamps == null) return; @@ -130,9 +136,8 @@ public class IndexingStamp { } } - private static final ConcurrentHashMap<VirtualFile, Timestamps> myTimestampsCache = new ConcurrentHashMap<VirtualFile, Timestamps>(); - private static final int CAPACITY = 100; - private static final ArrayBlockingQueue<VirtualFile> myFinishedFiles = new ArrayBlockingQueue<VirtualFile>(CAPACITY); + private static final ConcurrentMap<VirtualFile, Timestamps> myTimestampsCache = new ConcurrentHashMap<VirtualFile, Timestamps>(); + private static final BlockingQueue<VirtualFile> ourFinishedFiles = new ArrayBlockingQueue<VirtualFile>(100); public static boolean isFileIndexed(VirtualFile file, ID<?, ?> indexName, final long indexCreationStamp) { try { @@ -148,7 +153,7 @@ public class IndexingStamp { return false; } - public static long getIndexStamp(VirtualFile file, ID<?, ?> indexName) { + public static long getIndexStamp(@NotNull VirtualFile file, ID<?, ?> indexName) { synchronized (getStripedLock(file)) { Timestamps stamp = createOrGetTimeStamp(file); if (stamp != null) return stamp.get(indexName); @@ -156,7 +161,7 @@ public class IndexingStamp { } } - private static Timestamps createOrGetTimeStamp(VirtualFile file) { + private static Timestamps createOrGetTimeStamp(@NotNull VirtualFile file) { if (file instanceof NewVirtualFile && file.isValid()) { Timestamps timestamps = myTimestampsCache.get(file); if (timestamps == null) { @@ -174,7 +179,7 @@ public class IndexingStamp { return null; } - public static void update(final VirtualFile file, final ID<?, ?> indexName, final long indexCreationStamp) { + public static void update(@NotNull VirtualFile file, @NotNull ID<?, ?> indexName, final long indexCreationStamp) { synchronized (getStripedLock(file)) { try { Timestamps stamp = createOrGetTimeStamp(file); @@ -185,7 +190,7 @@ public class IndexingStamp { } } - public static void removeAllIndexedState(VirtualFile file) { + public static void removeAllIndexedState(@NotNull VirtualFile file) { synchronized (getStripedLock(file)) { if (file instanceof NewVirtualFile && file.isValid()) { myTimestampsCache.put(file, new Timestamps()); @@ -193,7 +198,8 @@ public class IndexingStamp { } } - public static Collection<ID<?,?>> getIndexedIds(final VirtualFile file) { + @NotNull + public static Collection<ID<?,?>> getIndexedIds(@NotNull VirtualFile file) { synchronized (getStripedLock(file)) { try { Timestamps stamp = createOrGetTimeStamp(file); @@ -220,17 +226,11 @@ public class IndexingStamp { } public static void flushCache(@Nullable VirtualFile finishedFile) { - if (finishedFile == null || !myFinishedFiles.offer(finishedFile)) { - VirtualFile[] files = null; - synchronized (myFinishedFiles) { - int size = myFinishedFiles.size(); - if ((finishedFile == null && size > 0) || size == CAPACITY) { - files = myFinishedFiles.toArray(new VirtualFile[size]); - myFinishedFiles.clear(); - } - } + if (finishedFile == null || !ourFinishedFiles.offer(finishedFile)) { + List<VirtualFile> files = new ArrayList<VirtualFile>(ourFinishedFiles.size()); + ourFinishedFiles.drainTo(files); - if (files != null) { + if (!files.isEmpty()) { for(VirtualFile file:files) { synchronized (getStripedLock(file)) { Timestamps timestamp = myTimestampsCache.remove(file); @@ -248,7 +248,7 @@ public class IndexingStamp { } } } - if (finishedFile != null) myFinishedFiles.offer(finishedFile); + if (finishedFile != null) ourFinishedFiles.offer(finishedFile); } } @@ -257,7 +257,7 @@ public class IndexingStamp { for(int i = 0; i < ourLocks.length; ++i) ourLocks[i] = new Object(); } - private static Object getStripedLock(VirtualFile file) { + private static Object getStripedLock(@NotNull VirtualFile file) { if (!(file instanceof NewVirtualFile)) return 0; int id = ((NewVirtualFile)file).getId(); return ourLocks[(id & 0xFF) % ourLocks.length]; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java b/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java index 649bd25730fb..bbd015507e24 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapIndexStorage.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. @@ -60,7 +60,7 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu private final Lock l = new ReentrantLock(); private final DataExternalizer<Value> myDataExternalizer; - private boolean myHighKeySelectivity; + private final boolean myHighKeySelectivity; private final LowMemoryWatcher myLowMemoryFlusher = LowMemoryWatcher.register(new Runnable() { @Override public void run() { @@ -70,7 +70,8 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu myCache.clear(); if (myMap.isDirty()) myMap.force(); } - } finally { + } + finally { l.unlock(); } } @@ -89,9 +90,7 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu @NotNull DataExternalizer<Value> valueExternalizer, final int cacheSize, boolean highKeySelectivity, - boolean buildKeyHashToVirtualFileMapping - ) throws IOException { - + boolean buildKeyHashToVirtualFileMapping) throws IOException { myStorageFile = storageFile; myKeyDescriptor = keyDescriptor; myCacheSize = cacheSize; @@ -150,6 +149,7 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu myKeyHashToVirtualFileMapping = myBuildKeyHashToVirtualFileMapping ? new KeyHash2VirtualFileEnumerator(getProjectFile()) : null; } + @NotNull private File getProjectFile() { return new File(myStorageFile.getPath() + ".project"); } @@ -222,7 +222,7 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu } @Override - public boolean processKeys(final Processor<Key> processor, GlobalSearchScope scope, final IdFilter idFilter) throws StorageException { + public boolean processKeys(@NotNull final Processor<Key> processor, GlobalSearchScope scope, final IdFilter idFilter) throws StorageException { l.lock(); try { myCache.clear(); // this will ensure that all new keys are made into the map @@ -298,7 +298,8 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu } } - private static TIntHashSet loadHashedIds(File fileWithCaches) throws IOException { + @NotNull + private static TIntHashSet loadHashedIds(@NotNull File fileWithCaches) throws IOException { DataInputStream inputStream = null; try { inputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(fileWithCaches))); @@ -315,12 +316,13 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu if (inputStream != null) { try { inputStream.close(); - } catch (IOException ex) {} + } + catch (IOException ignored) {} } } } - private void saveHashedIds(TIntHashSet hashMaskSet, int largestId, GlobalSearchScope scope) { + private void saveHashedIds(@NotNull TIntHashSet hashMaskSet, int largestId, @NotNull GlobalSearchScope scope) { File newFileWithCaches = getSavedProjectFileValueIds(largestId, scope); assert newFileWithCaches != null; DataOutputStream stream = null; @@ -341,17 +343,22 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu } }); if (result) myLastScannedId = largestId; - } catch (IOException ex) {} + } + catch (IOException ignored) { + + } finally { if (stream != null) { try { stream.close(); - } catch (IOException ex) {} + } + catch (IOException ignored) {} } } } - private @Nullable File getSavedProjectFileValueIds(int id, GlobalSearchScope scope) { + @Nullable + private File getSavedProjectFileValueIds(int id, @NotNull GlobalSearchScope scope) { Project project = scope.getProject(); if (project == null) return null; return new File(myStorageFile.getPath() + ".project."+project.hashCode() + "."+id + "." + scope.isSearchInLibraries()); @@ -423,7 +430,7 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu } @Override - public void removeAllValues(Key key, int inputId) throws StorageException { + public void removeAllValues(@NotNull Key key, int inputId) throws StorageException { try { myMap.markDirty(); // important: assuming the key exists in the index @@ -436,13 +443,13 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu private static class IntPairInArrayKeyDescriptor implements KeyDescriptor<int[]>, DifferentSerializableBytesImplyNonEqualityPolicy { @Override - public void save(DataOutput out, int[] value) throws IOException { + public void save(@NotNull DataOutput out, int[] value) throws IOException { DataInputOutputUtil.writeINT(out, value[0]); DataInputOutputUtil.writeINT(out, value[1]); } @Override - public int[] read(DataInput in) throws IOException { + public int[] read(@NotNull DataInput in) throws IOException { return new int[] {DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in)}; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java index f49f70db83bd..a19e2d92cddf 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.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. @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.NotNullComputable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.psi.search.GlobalSearchScope; @@ -33,8 +34,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.*; -import java.util.concurrent.Callable; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -146,18 +149,20 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val } } + @NotNull @Override public final Lock getReadLock() { return myLock.readLock(); } + @NotNull @Override public final Lock getWriteLock() { return myLock.writeLock(); } @Override - public boolean processAllKeys(Processor<Key> processor, GlobalSearchScope scope, IdFilter idFilter) throws StorageException { + public boolean processAllKeys(@NotNull Processor<Key> processor, @NotNull GlobalSearchScope scope, IdFilter idFilter) throws StorageException { final Lock lock = getReadLock(); try { lock.lock(); @@ -170,7 +175,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val @Override @NotNull - public ValueContainer<Value> getData(final Key key) throws StorageException { + public ValueContainer<Value> getData(@NotNull final Key key) throws StorageException { final Lock lock = getReadLock(); try { lock.lock(); @@ -203,6 +208,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val return null; } + @NotNull @Override public final Computable<Boolean> update(final int inputId, @Nullable final Input content) { @@ -219,17 +225,24 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val @Override public void run() { try { - updateWithMap(inputId, data, new Callable<Collection<Key>>() { + updateWithMap(inputId, data, new NotNullComputable<Collection<Key>>() { + @NotNull @Override - public Collection<Key> call() throws Exception { + public Collection<Key> compute() { if (myInputsIndex == null) { return new SmartList<Key>((Key)(Integer)inputId); } - final Collection<Key> oldKeys = myInputsIndex.get(inputId); - return oldKeys == null? Collections.<Key>emptyList() : oldKeys; + try { + Collection<Key> oldKeys = myInputsIndex.get(inputId); + return oldKeys == null? Collections.<Key>emptyList() : oldKeys; + } + catch (IOException e) { + throw new RuntimeException(e); + } } }); - } catch (StorageException ex) { + } + catch (StorageException ex) { exRef.set(ex); } } @@ -239,20 +252,19 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val LOG.info(exRef.get()); FileBasedIndex.getInstance().requestRebuild(myIndexId); return Boolean.FALSE; - } else { - return Boolean.TRUE; } + return Boolean.TRUE; } }; } protected void updateWithMap(final int inputId, @NotNull Map<Key, Value> newData, - @NotNull Callable<Collection<Key>> oldKeysGetter) throws StorageException { + @NotNull NotNullComputable<Collection<Key>> oldKeysGetter) throws StorageException { getWriteLock().lock(); try { try { - for (Key key : oldKeysGetter.call()) { + for (Key key : oldKeysGetter.compute()) { myStorage.removeAllValues(key, inputId); } } @@ -277,7 +289,8 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val } }); if (!b) throw exceptionRef.get(); - } else { + } + else { for (Map.Entry<Key, Value> entry : newData.entrySet()) { myStorage.addValue(entry.getKey(), inputId, entry.getValue()); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MemoryIndexStorage.java b/platform/lang-impl/src/com/intellij/util/indexing/MemoryIndexStorage.java index 3ef7d2ac4e98..2ae474b73858 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MemoryIndexStorage.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MemoryIndexStorage.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. @@ -34,6 +34,7 @@ import java.util.concurrent.atomic.AtomicBoolean; */ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value> { private final Map<Key, ChangeTrackingValueContainer<Value>> myMap = new HashMap<Key, ChangeTrackingValueContainer<Value>>(); + @NotNull private final IndexStorage<Key, Value> myBackendStorage; private final List<BufferingStateListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private final AtomicBoolean myBufferingEnabled = new AtomicBoolean(false); @@ -44,19 +45,20 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value> void memoryStorageCleared(); } - public MemoryIndexStorage(IndexStorage<Key, Value> backend) { + public MemoryIndexStorage(@NotNull IndexStorage<Key, Value> backend) { myBackendStorage = backend; } + @NotNull public IndexStorage<Key, Value> getBackendStorage() { return myBackendStorage; } - public void addBufferingStateListsner(BufferingStateListener listener) { + public void addBufferingStateListener(@NotNull BufferingStateListener listener) { myListeners.add(listener); } - public void removeBufferingStateListsner(BufferingStateListener listener) { + public void removeBufferingStateListener(@NotNull BufferingStateListener listener) { myListeners.remove(listener); } @@ -99,6 +101,7 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value> myBackendStorage.flush(); } + @NotNull @Override public Collection<Key> getKeys() throws StorageException { final Set<Key> keys = new HashSet<Key>(); @@ -107,7 +110,7 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value> } @Override - public boolean processKeys(final Processor<Key> processor, GlobalSearchScope scope, IdFilter idFilter) throws StorageException { + public boolean processKeys(@NotNull final Processor<Key> processor, GlobalSearchScope scope, IdFilter idFilter) throws StorageException { final Set<Key> stopList = new HashSet<Key>(); Processor<Key> decoratingProcessor = new Processor<Key>() { @@ -129,7 +132,7 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value> } stopList.add(key); } - return myBackendStorage.processKeys(stopList.size() == 0 && myMap.size() == 0 ? processor : decoratingProcessor, scope, idFilter); + return myBackendStorage.processKeys(stopList.isEmpty() && myMap.isEmpty() ? processor : decoratingProcessor, scope, idFilter); } @Override @@ -147,7 +150,7 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value> } @Override - public void removeAllValues(Key key, int inputId) throws StorageException { + public void removeAllValues(@NotNull Key key, int inputId) throws StorageException { if (myBufferingEnabled.get()) { getMemValueContainer(key).removeAssociatedValue(inputId); return; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index 2a18906d80f8..a4975f100d96 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.CollectingContentIterator; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -49,8 +50,9 @@ public class UnindexedFilesUpdater implements CacheUpdater { return myIndex.getNumberOfPendingInvalidations(); } + @NotNull @Override - public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { + public VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator) { myIndex.filesUpdateStarted(myProject); CollectingContentIterator finder = myIndex.createContentIterator(indicator); long l = System.currentTimeMillis(); @@ -66,10 +68,11 @@ public class UnindexedFilesUpdater implements CacheUpdater { } @Override - public void processFile(final FileContent fileContent) { + public void processFile(@NotNull FileContent fileContent) { try { myIndex.indexFileContent(myProject, fileContent); - } finally { + } + finally { IndexingStamp.flushCache(fileContent.getVirtualFile()); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java index 589db0f47e58..4b431eddb5d7 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.intellij.util.indexing; import com.intellij.openapi.util.Computable; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.concurrent.locks.Lock; @@ -31,12 +32,13 @@ public interface UpdatableIndex<Key, Value, Input> extends AbstractIndex<Key,Val void flush() throws StorageException; - /** - */ + @NotNull Computable<Boolean> update(int inputId, @Nullable Input content); - + + @NotNull Lock getReadLock(); - + + @NotNull Lock getWriteLock(); void dispose(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java index d901751fadf4..47efe30fbf84 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.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. @@ -16,6 +16,8 @@ package com.intellij.util.indexing; +import org.jetbrains.annotations.NotNull; + import java.util.Iterator; import java.util.List; @@ -35,15 +37,19 @@ public abstract class ValueContainer<Value> { abstract static class IntPredicate { abstract boolean contains(int id); } - + + @NotNull public abstract IntIterator getInputIdsIterator(Value value); public abstract boolean isAssociated(Value value, int inputId); + @NotNull public abstract IntPredicate getValueAssociationPredicate(Value value); + @NotNull public abstract Iterator<Value> getValueIterator(); + @NotNull public abstract List<Value> toValueList(); public abstract int size(); @@ -53,7 +59,7 @@ public abstract class ValueContainer<Value> { boolean perform(int id, T value); } - public final boolean forEach(final ContainerAction<Value> action) { + public final boolean forEach(@NotNull ContainerAction<Value> action) { for (final Iterator<Value> valueIterator = getValueIterator(); valueIterator.hasNext();) { final Value value = valueIterator.next(); for (final IntIterator intIterator = getInputIdsIterator(value); intIterator.hasNext();) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java index ae9424d7733e..ddc538154177 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.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. @@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.SmartList; import com.intellij.util.containers.EmptyIterator; import gnu.trove.*; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -139,6 +140,7 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> implement return true; } + @NotNull @Override public Iterator<Value> getValueIterator() { if (myInputIdMapping != null) { @@ -190,6 +192,7 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> implement } } + @NotNull @Override public List<Value> toValueList() { if (myInputIdMapping == null) { @@ -216,6 +219,7 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> implement return false; } + @NotNull @Override public IntPredicate getValueAssociationPredicate(Value value) { final Object input = getInput(value); @@ -247,6 +251,7 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> implement }; } + @NotNull @Override public IntIterator getInputIdsIterator(Value value) { final Object input = getInput(value); @@ -335,6 +340,7 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> implement } }; + @NotNull public ValueContainerImpl<Value> copy() { ValueContainerImpl<Value> container = new ValueContainerImpl<Value>(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java index c4385b491733..3bf0ece67a99 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java @@ -1,3 +1,18 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.util.indexing; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; @@ -71,7 +86,7 @@ class ValueContainerMap<Key, Value> extends PersistentHashMap<Key, ValueContaine } @Override - public void save(final DataOutput out, @NotNull final ValueContainer<T> container) throws IOException { + public void save(@NotNull final DataOutput out, @NotNull final ValueContainer<T> container) throws IOException { saveImpl(out, container); } @@ -79,29 +94,24 @@ class ValueContainerMap<Key, Value> extends PersistentHashMap<Key, ValueContaine DataInputOutputUtil.writeSINT(out, -inputId); } - private void saveImpl(final DataOutput out, @NotNull final ValueContainer<T> container) throws IOException { + private void saveImpl(@NotNull DataOutput out, @NotNull final ValueContainer<T> container) throws IOException { DataInputOutputUtil.writeSINT(out, container.size()); for (final Iterator<T> valueIterator = container.getValueIterator(); valueIterator.hasNext();) { final T value = valueIterator.next(); myExternalizer.save(out, value); final ValueContainer.IntIterator ids = container.getInputIdsIterator(value); - if (ids != null) { - DataInputOutputUtil.writeSINT(out, ids.size()); - while (ids.hasNext()) { - final int id = ids.next(); - DataInputOutputUtil.writeSINT(out, id); - } - } - else { - DataInputOutputUtil.writeSINT(out, 0); + DataInputOutputUtil.writeSINT(out, ids.size()); + while (ids.hasNext()) { + final int id = ids.next(); + DataInputOutputUtil.writeSINT(out, id); } } } @NotNull @Override - public ValueContainerImpl<T> read(final DataInput in) throws IOException { + public ValueContainerImpl<T> read(@NotNull final DataInput in) throws IOException { DataInputStream stream = (DataInputStream)in; final ValueContainerImpl<T> valueContainer = new ValueContainerImpl<T>(); diff --git a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java index f394c836475d..6dd7aebfe2d5 100644 --- a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java +++ b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java @@ -2,6 +2,7 @@ package com.intellij.webcore.packaging; import com.google.common.collect.Lists; import com.intellij.icons.AllIcons; +import com.intellij.ide.ActivityTracker; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; @@ -397,6 +398,9 @@ public class InstalledPackagesPanel extends JPanel { myPackagesTable.setPaintBusy(false); myPackagesTable.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT); updateUninstallUpgrade(); + // Action button presentations won't be updated if no events occur (e.g. mouse isn't moving, keys aren't being pressed). + // In that case emulating activity will help: + ActivityTracker.getInstance().inc(); } public void doUpdatePackages(@NotNull final PackageManagementService packageManagementService) { diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/IdeaGateway.java b/platform/lvcs-impl/src/com/intellij/history/integration/IdeaGateway.java index 3c307500d6ce..24a7603e45f7 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/IdeaGateway.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/IdeaGateway.java @@ -30,7 +30,10 @@ import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Clock; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.encoding.EncodingRegistry; diff --git a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java index a42a1bfab18a..445ac0126047 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java @@ -240,7 +240,7 @@ public class GeneralCommandLine implements UserDataHolder { commands = CommandLineUtil.toCommandLine(myExePath, myProgramParams.getList()); } catch (ExecutionException e) { - LOG.warn(e); + LOG.info(e); throw e; } @@ -248,7 +248,7 @@ public class GeneralCommandLine implements UserDataHolder { return startProcess(commands); } catch (IOException e) { - LOG.warn(e); + LOG.info(e); throw new ProcessNotCreatedException(e.getMessage(), e, this); } } diff --git a/platform/platform-api/src/com/intellij/ide/caches/CacheUpdater.java b/platform/platform-api/src/com/intellij/ide/caches/CacheUpdater.java index 219f23bced4f..359924225981 100644 --- a/platform/platform-api/src/com/intellij/ide/caches/CacheUpdater.java +++ b/platform/platform-api/src/com/intellij/ide/caches/CacheUpdater.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. @@ -18,13 +18,15 @@ package com.intellij.ide.caches; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; public interface CacheUpdater { int getNumberOfPendingUpdateJobs(); - VirtualFile[] queryNeededFiles(ProgressIndicator indicator); + @NotNull + VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator); - void processFile(FileContent fileContent); + void processFile(@NotNull FileContent fileContent); void updatingDone(); diff --git a/platform/platform-api/src/com/intellij/lang/LanguageDialect.java b/platform/platform-api/src/com/intellij/lang/LanguageDialect.java index 532d4d89da17..f5bc6b2bceea 100644 --- a/platform/platform-api/src/com/intellij/lang/LanguageDialect.java +++ b/platform/platform-api/src/com/intellij/lang/LanguageDialect.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. @@ -18,6 +18,8 @@ package com.intellij.lang; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +/** @deprecated use {@linkplain Language#Language(Language, String, String...)} (to remove in IDEA 15) */ +@SuppressWarnings("UnusedDeclaration") public abstract class LanguageDialect extends Language { public LanguageDialect(@NonNls @NotNull String id, @NotNull Language baseLanguage) { super(baseLanguage, id, ""); diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/EmptyAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/EmptyAction.java index 4ae67c9da5d7..9e53c35f7cac 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/EmptyAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/EmptyAction.java @@ -15,11 +15,11 @@ */ package com.intellij.openapi.actionSystem; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.ArrayList; /** * This class purpose is to reserve action-id in a plugin.xml so the action appears in Keymap. @@ -74,13 +74,8 @@ public final class EmptyAction extends AnAction { } public static void registerActionShortcuts(JComponent component, final JComponent fromComponent) { - @SuppressWarnings("unchecked") - final ArrayList<AnAction> actionList = - (ArrayList<AnAction>)fromComponent.getClientProperty(ourClientProperty); - if (actionList != null) { - for (AnAction anAction : actionList) { - anAction.registerCustomShortcutSet(anAction.getShortcutSet(), component); - } + for (AnAction anAction : ActionUtil.getActions(fromComponent)) { + anAction.registerCustomShortcutSet(anAction.getShortcutSet(), component); } } diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java index b515b84e8f3f..2004b55c66d4 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java @@ -115,7 +115,8 @@ public interface IdeActions { @NonNls String ACTION_FIND_NEXT = "FindNext"; @NonNls String ACTION_FIND_PREVIOUS = "FindPrevious"; @NonNls String ACTION_SELECT_NEXT_OCCURENCE = "SelectNextOccurrence"; - @NonNls String ACTION_UNSELECT_LAST_OCCURENCE = "UnselectLastOccurrence"; + @NonNls String ACTION_SELECT_ALL_OCCURRENCES = "SelectAllOccurrences"; + @NonNls String ACTION_UNSELECT_PREVIOUS_OCCURENCE = "UnselectPreviousOccurrence"; @NonNls String ACTION_COMPILE = "Compile"; @NonNls String ACTION_COMPILE_PROJECT = "CompileProject"; @NonNls String ACTION_MAKE_MODULE = "MakeModule"; @@ -189,6 +190,8 @@ public interface IdeActions { @NonNls String GROUP_OTHER_MENU = "OtherMenu"; @NonNls String GROUP_EDITOR = "EditorActions"; @NonNls String GROUP_DEBUGGER = "DebuggerActions"; + + @NonNls String ACTION_TOGGLE_LINE_BREAKPOINT = "ToggleLineBreakpoint"; @NonNls String ACTION_REFRESH = "Refresh"; diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ActionUtil.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ActionUtil.java index 8132f9e65990..e0dc548fd452 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ActionUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ActionUtil.java @@ -27,7 +27,9 @@ import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class ActionUtil { @@ -166,5 +168,10 @@ public class ActionUtil { } } - + @NotNull + public static List<AnAction> getActions(@NotNull JComponent component) { + Object property = component.getClientProperty(AnAction.ourClientProperty); + //noinspection unchecked + return property == null ? Collections.<AnAction>emptyList() : (List<AnAction>)property; + } } diff --git a/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java b/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java index 55960fb8296e..9a0af4ad83a2 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.fileEditor.OpenFileDescriptor; @@ -29,8 +30,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; -import java.nio.charset.Charset; import java.nio.ByteBuffer; +import java.nio.charset.Charset; /** * Allows to compare some text not associated with file or document. @@ -210,16 +211,18 @@ public class SimpleContent extends DiffContent { private static class LineSeparators { private String mySeparator; - public String correctText(String text) { - LineTokenizer lineTokenizer = new LineTokenizer(text); - String[] lines = lineTokenizer.execute(); + @NotNull + public String correctText(@NotNull String text) { + DiffString.LineTokenizer lineTokenizer = new DiffString.LineTokenizer(DiffString.create(text)); + DiffString[] lines = lineTokenizer.execute(); mySeparator = lineTokenizer.getLineSeparator(); LOG.assertTrue(mySeparator == null || !mySeparator.isEmpty()); if (mySeparator == null) mySeparator = SystemProperties.getLineSeparator(); - return LineTokenizer.concatLines(lines); + return DiffString.concatenate(lines).toString(); } - public String restoreText(String text) { + @NotNull + public String restoreText(@NotNull String text) { if (mySeparator == null) throw new NullPointerException(); return text.replaceAll("\n", mySeparator); } diff --git a/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java b/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java index cf674d6abe72..8058f6c754a9 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.psi.PsiDocumentManager; import com.intellij.util.Producer; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.datatransfer.DataFlavor; @@ -45,12 +46,27 @@ public class EditorModificationUtil { int selectionStart = selectionModel.getSelectionStart(); int selectionEnd = selectionModel.getSelectionEnd(); - editor.getCaretModel().moveToOffset(selectionStart); + VisualPosition selectionStartPosition = selectionModel.getSelectionStartPosition(); + if (editor.isColumnMode() && editor.getCaretModel().supportsMultipleCarets() && selectionStartPosition != null) { + editor.getCaretModel().moveToVisualPosition(selectionStartPosition); + } + else { + editor.getCaretModel().moveToOffset(selectionStart); + } selectionModel.removeSelection(); editor.getDocument().deleteString(selectionStart, selectionEnd); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } + public static void deleteSelectedTextForAllCarets(@NotNull final Editor editor) { + editor.getCaretModel().runForEachCaret(new CaretAction() { + @Override + public void perform(Caret caret) { + deleteSelectedText(editor); + } + }); + } + public static void deleteBlockSelection(Editor editor) { SelectionModel selectionModel = editor.getSelectionModel(); if (!selectionModel.hasBlockSelection()) return; @@ -81,14 +97,24 @@ public class EditorModificationUtil { editor.getSelectionModel().setBlockSelection(new LogicalPosition(startLine, caretColumn), new LogicalPosition(endLine, caretColumn)); } - public static void insertStringAtCaret(Editor editor, String s) { + public static void insertStringAtCaret(Editor editor, @NotNull String s) { insertStringAtCaret(editor, s, false, true); } - public static int insertStringAtCaret(Editor editor, String s, boolean toProcessOverwriteMode, boolean toMoveCaret) { + public static int insertStringAtCaret(Editor editor, @NotNull String s, boolean toProcessOverwriteMode, boolean toMoveCaret) { + return insertStringAtCaret(editor, s, toProcessOverwriteMode, toMoveCaret, s.length()); + } + + public static int insertStringAtCaret(Editor editor, @NotNull String s, boolean toProcessOverwriteMode, boolean toMoveCaret, int caretShift) { final SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasSelection()) { - editor.getCaretModel().moveToOffset(selectionModel.getSelectionStart(), true); + VisualPosition startPosition = selectionModel.getSelectionStartPosition(); + if (editor.isColumnMode() && editor.getCaretModel().supportsMultipleCarets() && startPosition != null) { + editor.getCaretModel().moveToVisualPosition(startPosition); + } + else { + editor.getCaretModel().moveToOffset(selectionModel.getSelectionStart(), true); + } } // There is a possible case that particular soft wraps become hard wraps if the caret is located at soft wrap-introduced virtual @@ -120,7 +146,7 @@ public class EditorModificationUtil { document.replaceString(oldOffset, Math.min(endOffset, oldOffset + s.length()), s); } - int offset = oldOffset + s.length(); + int offset = oldOffset + filler.length() + caretShift; if (toMoveCaret){ editor.getCaretModel().moveToOffset(offset, true); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); @@ -139,7 +165,7 @@ public class EditorModificationUtil { if (text == null) return null; if (editor.getCaretModel().supportsMultipleCarets()) { - int caretCount = editor.getCaretModel().getAllCarets().size(); + int caretCount = editor.getCaretModel().getCaretCount(); final Iterator<String> segments = new ClipboardTextPerCaretSplitter().split(text, caretCount).iterator(); editor.getCaretModel().runForEachCaret(new CaretAction() { @Override @@ -365,6 +391,62 @@ public class EditorModificationUtil { } } + public static void typeInStringAtCaretHonorMultipleCarets(final Editor editor, @NotNull final String str, final boolean toProcessOverwriteMode) { + typeInStringAtCaretHonorMultipleCarets(editor, str, toProcessOverwriteMode, str.length()); + } + + /** + * Inserts given string at each caret's position. Effective caret shift will be equal to <code>caretShift</code> for each caret. + */ + public static void typeInStringAtCaretHonorMultipleCarets(final Editor editor, @NotNull final String str, final boolean toProcessOverwriteMode, final int caretShift) + throws ReadOnlyFragmentModificationException + { + Document doc = editor.getDocument(); + final SelectionModel selectionModel = editor.getSelectionModel(); + if (selectionModel.hasBlockSelection()) { + RangeMarker guard = selectionModel.getBlockSelectionGuard(); + if (guard != null) { + DocumentEvent evt = new MockDocumentEvent(doc, editor.getCaretModel().getOffset()); + ReadOnlyFragmentModificationException e = new ReadOnlyFragmentModificationException(evt, guard); + EditorActionManager.getInstance().getReadonlyFragmentModificationHandler(doc).handle(e); + } + else { + final LogicalPosition start = selectionModel.getBlockStart(); + final LogicalPosition end = selectionModel.getBlockEnd(); + assert start != null; + assert end != null; + + int column = Math.min(start.column, end.column); + int startLine = Math.min(start.line, end.line); + int endLine = Math.max(start.line, end.line); + deleteBlockSelection(editor); + for (int i = startLine; i <= endLine; i++) { + editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(i, column)); + insertStringAtCaret(editor, str, toProcessOverwriteMode, true, caretShift); + } + selectionModel.setBlockSelection(new LogicalPosition(startLine, column + str.length()), + new LogicalPosition(endLine, column + str.length())); + } + } + else { + editor.getCaretModel().runForEachCaret(new CaretAction() { + @Override + public void perform(Caret caret) { + insertStringAtCaret(editor, str, toProcessOverwriteMode, true, caretShift); + } + }); + } + } + + public static void moveAllCaretsRelatively(@NotNull Editor editor, final int caretShift) { + editor.getCaretModel().runForEachCaret(new CaretAction() { + @Override + public void perform(Caret caret) { + caret.moveToOffset(caret.getOffset() + caretShift); + } + }); + } + /** @deprecated use {@link #pasteTransferable(Editor, Producer)} (to remove in IDEA 14) */ @SuppressWarnings("UnusedDeclaration") public static TextRange pasteFromClipboard(Editor editor) { diff --git a/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java b/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java index 0c468aa373eb..f296c643d5bb 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java @@ -17,7 +17,7 @@ package com.intellij.openapi.editor; import com.intellij.codeStyle.CodeStyleFacade; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -36,11 +36,13 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentMap; -public class LazyRangeMarkerFactory extends AbstractProjectComponent { +public class LazyRangeMarkerFactory { + private final Project myProject; private final ConcurrentMap<VirtualFile,WeakList<LazyMarker>> myMarkers = new ConcurrentWeakHashMap<VirtualFile, WeakList<LazyMarker>>(); public LazyRangeMarkerFactory(@NotNull Project project, @NotNull final FileDocumentManager fileDocumentManager) { - super(project); + myProject = project; + EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentAdapter() { @Override public void beforeDocumentChange(DocumentEvent e) { @@ -71,7 +73,7 @@ public class LazyRangeMarkerFactory extends AbstractProjectComponent { } public static LazyRangeMarkerFactory getInstance(Project project) { - return project.getComponent(LazyRangeMarkerFactory.class); + return ServiceManager.getService(project, LazyRangeMarkerFactory.class); } @NotNull @@ -92,8 +94,7 @@ public class LazyRangeMarkerFactory extends AbstractProjectComponent { return ApplicationManager.getApplication().runReadAction(new Computable<RangeMarker>() { @Override public RangeMarker compute() { - FileDocumentManager fdm = FileDocumentManager.getInstance(); - final Document document = fdm.getCachedDocument(file); + final Document document = FileDocumentManager.getInstance().getCachedDocument(file); if (document != null) { final int offset = calculateOffset(myProject, file, document, line, column); return document.createRangeMarker(offset, offset, persistent); @@ -122,7 +123,7 @@ public class LazyRangeMarkerFactory extends AbstractProjectComponent { } @Nullable - private RangeMarker getOrCreateDelegate() { + protected final RangeMarker getOrCreateDelegate() { if (myDelegate == null) { Document document = FileDocumentManager.getInstance().getDocument(myFile); if (document == null) { @@ -218,6 +219,18 @@ public class LazyRangeMarkerFactory extends AbstractProjectComponent { return document.createRangeMarker(offset, offset); } + + @Override + public int getStartOffset() { + getOrCreateDelegate(); + return super.getStartOffset(); + } + + @Override + public int getEndOffset() { + getOrCreateDelegate(); + return super.getEndOffset(); + } } private static int calculateOffset(@NotNull Project project, @NotNull VirtualFile file, @NotNull Document document, final int line, final int column) { diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedAction.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedAction.java index 28bc0f0510ed..1e49937e7765 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedAction.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedAction.java @@ -64,18 +64,7 @@ public class TypedAction { try { final String str = String.valueOf(charTyped); CommandProcessor.getInstance().setCurrentCommandName(EditorBundle.message("typing.in.editor.command.name")); - - if (editor.getCaretModel().getAllCarets().size() == 1) { // temporary fix for completion - going forward we shouldn't use this check - EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(editor, str, true); - } - else { - editor.getCaretModel().runForEachCaret(new CaretAction() { - @Override - public void perform(Caret caret) { - EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(editor, str, true); - } - }); - } + EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, str, true); } catch (ReadOnlyFragmentModificationException e) { EditorActionManager.getInstance().getReadonlyFragmentModificationHandler(doc).handle(e); diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java index 9561581bc38b..c9e3a0f2145a 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java +++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java @@ -55,31 +55,38 @@ public class OpenFileDescriptor implements Navigatable { private boolean myUseCurrentWindow = false; public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int offset) { - this(project, file, -1, -1, offset, false); + this(project, file, -1, -1, offset, null, false); } public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int logicalLine, int logicalColumn) { - this(project, file, logicalLine, logicalColumn, -1, false); + this(project, file, logicalLine, logicalColumn, -1, null, false); } public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int logicalLine, int logicalColumn, boolean persistent) { - this(project, file, logicalLine, logicalColumn, -1, persistent); + this(project, file, logicalLine, logicalColumn, -1, null, persistent); } public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file) { - this(project, file, -1, -1, -1, false); + this(project, file, -1, -1, -1, null, false); + } + + public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, @NotNull RangeMarker rangeMarker) { + this(project, file, -1, -1, -1, rangeMarker, false); } private OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, - int logicalLine, int logicalColumn, int offset, boolean persistent) { + int logicalLine, int logicalColumn, int offset, @Nullable RangeMarker rangeMarker, boolean persistent) { myProject = project; myFile = file; myLogicalLine = logicalLine; myLogicalColumn = logicalColumn; myOffset = offset; - if (offset >= 0) { + if (rangeMarker != null) { + myRangeMarker = rangeMarker; + } + else if (offset >= 0) { myRangeMarker = LazyRangeMarkerFactory.getInstance(project).createRangeMarker(file, offset); } else if (logicalLine >= 0 ){ diff --git a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java index b4502de5090c..30788880ff66 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java @@ -219,7 +219,7 @@ public class Messages { /** * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel */ - public static int showDialog(Component parent, String message, @NotNull String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon) { + public static int showDialog(@NotNull Component parent, String message, @NotNull String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon) { if (isApplicationInUnitTestOrHeadless()) { return ourTestImplementation.show(message); } @@ -309,7 +309,7 @@ public class Messages { showDialog(project, message, title, new String[]{OK_BUTTON}, 0, icon); } - public static void showMessageDialog(Component parent, String message, @NotNull String title, @Nullable Icon icon) { + public static void showMessageDialog(@NotNull Component parent, String message, @NotNull String title, @Nullable Icon icon) { try { if (canShowMacSheetPanel()) { MacMessages.getInstance().showOkMessageDialog(title, message, OK_BUTTON, SwingUtilities.getWindowAncestor(parent)); @@ -386,7 +386,7 @@ public class Messages { * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button. */ @YesNoResult - public static int showYesNoDialog(Component parent, String message, @NotNull String title, @Nullable Icon icon) { + public static int showYesNoDialog(@NotNull Component parent, String message, @NotNull String title, @Nullable Icon icon) { try { if (canShowMacSheetPanel()) { return MacMessages.getInstance().showYesNoDialog(title, message, YES_BUTTON, NO_BUTTON, SwingUtilities.getWindowAncestor(parent)); @@ -508,7 +508,7 @@ public class Messages { * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button. */ @OkCancelResult - public static int showOkCancelDialog(Component parent, String message, @NotNull String title, @NotNull String okText, @NotNull String cancelText, Icon icon) { + public static int showOkCancelDialog(@NotNull Component parent, String message, @NotNull String title, @NotNull String okText, @NotNull String cancelText, Icon icon) { try { if (canShowMacSheetPanel()) { int result = @@ -526,7 +526,7 @@ public class Messages { * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button. */ @OkCancelResult - public static int showOkCancelDialog(Component parent, String message, String title, Icon icon) { + public static int showOkCancelDialog(@NotNull Component parent, String message, String title, Icon icon) { return showOkCancelDialog(parent, message, title, OK_BUTTON, CANCEL_BUTTON, icon); } @@ -619,7 +619,7 @@ public class Messages { showDialog(project, message, title, new String[]{OK_BUTTON}, 0, getErrorIcon()); } - public static void showErrorDialog(Component component, String message, @Nls @NotNull String title) { + public static void showErrorDialog(@NotNull Component component, String message, @Nls @NotNull String title) { try { if (canShowMacSheetPanel()) { MacMessages.getInstance().showErrorDialog(title, message, OK_BUTTON, SwingUtilities.getWindowAncestor(component)); @@ -632,7 +632,7 @@ public class Messages { showDialog(component, message, title, new String[]{OK_BUTTON}, 0, getErrorIcon()); } - public static void showErrorDialog(Component component, String message) { + public static void showErrorDialog(@NotNull Component component, String message) { try { if (canShowMacSheetPanel()) { MacMessages.getInstance().showErrorDialog(CommonBundle.getErrorTitle(), message, OK_BUTTON, SwingUtilities.getWindowAncestor( @@ -678,7 +678,7 @@ public class Messages { showDialog(project, message, title, new String[]{OK_BUTTON}, 0, getWarningIcon()); } - public static void showWarningDialog(Component component, String message, @NotNull String title) { + public static void showWarningDialog(@NotNull Component component, String message, @NotNull String title) { try { if (canShowMacSheetPanel()) { MacMessages.getInstance().showErrorDialog(title, message, OK_BUTTON, SwingUtilities.getWindowAncestor(component)); @@ -751,7 +751,7 @@ public class Messages { * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button. */ @YesNoCancelResult - public static int showYesNoCancelDialog(Component parent, + public static int showYesNoCancelDialog(@NotNull Component parent, String message, @NotNull String title, @NotNull String yes, @@ -775,7 +775,7 @@ public class Messages { * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button. */ @YesNoCancelResult - public static int showYesNoCancelDialog(Component parent, String message, String title, Icon icon) { + public static int showYesNoCancelDialog(@NotNull Component parent, String message, String title, Icon icon) { return showYesNoCancelDialog(parent, message, title, YES_BUTTON, NO_BUTTON, CANCEL_BUTTON, icon); } @@ -878,7 +878,7 @@ public class Messages { * @return trimmed input string or <code>null</code> if user cancelled dialog. */ @Nullable - public static String showInputDialog(Component parent, String message, String title, @Nullable Icon icon) { + public static String showInputDialog(@NotNull Component parent, String message, String title, @Nullable Icon icon) { return showInputDialog(parent, message, title, icon, null, null); } @@ -942,7 +942,7 @@ public class Messages { } @Nullable - public static String showInputDialog(Component parent, + public static String showInputDialog(@NotNull Component parent, String message, String title, @Nullable Icon icon, @@ -1051,7 +1051,7 @@ public class Messages { /** @deprecated It looks awful! */ @Deprecated - public static int showChooseDialog(Component parent, String message, String title, String[] values, String initialValue, Icon icon) { + public static int showChooseDialog(@NotNull Component parent, String message, String title, String[] values, String initialValue, Icon icon) { if (isApplicationInUnitTestOrHeadless()) { return ourTestImplementation.show(message); } @@ -1250,15 +1250,15 @@ public class Messages { _init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, null); } - public MessageDialog(Component parent, String message, String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon) { + public MessageDialog(@NotNull Component parent, String message, String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon) { this(parent, message, title, options, defaultOptionIndex, icon, false); } - public MessageDialog(Component parent, String message, String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon, boolean canBeParent) { + public MessageDialog(@NotNull Component parent, String message, String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon, boolean canBeParent) { this(parent, message, title, options, defaultOptionIndex, -1, icon, canBeParent); } - public MessageDialog(Component parent, + public MessageDialog(@NotNull Component parent, String message, String title, @NotNull String[] options, @@ -1644,7 +1644,7 @@ public class Messages { this(project, message, title, icon, initialValue, validator, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0); } - public InputDialog(Component parent, + public InputDialog(@NotNull Component parent, String message, String title, @Nullable Icon icon, @@ -1881,7 +1881,7 @@ public class Messages { this(project, message, title, icon, values, initialValue, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0); } - public ChooseDialog(Component parent, String message, String title, @Nullable Icon icon, String[] values, String initialValue) { + public ChooseDialog(@NotNull Component parent, String message, String title, @Nullable Icon icon, String[] values, String initialValue) { super(parent, message, title, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0, icon); myComboBox.setModel(new DefaultComboBoxModel(values)); myComboBox.setSelectedItem(initialValue); diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/impl/StubVirtualFile.java b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/impl/StubVirtualFile.java index 48765456e681..7d391758cfdb 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/impl/StubVirtualFile.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/impl/StubVirtualFile.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. @@ -30,69 +30,85 @@ import java.io.InputStream; import java.io.OutputStream; public class StubVirtualFile extends VirtualFile { + @Override @NotNull public byte[] contentsToByteArray() throws IOException { throw new UnsupportedOperationException("contentsToByteArray is not implemented"); } + @Override public VirtualFile[] getChildren() { throw new UnsupportedOperationException("getChildren is not implemented"); } + @Override @NotNull public VirtualFileSystem getFileSystem() { throw new UnsupportedOperationException("getFileSystem is not implemented"); } + @Override public InputStream getInputStream() throws IOException { throw new UnsupportedOperationException("getInputStream is not implemented"); } + @Override public long getLength() { throw new UnsupportedOperationException("getLength is not implemented"); } + @Override @NotNull @NonNls public String getName() { throw new UnsupportedOperationException("getName is not implemented"); } + @Override @NotNull public OutputStream getOutputStream(final Object requestor, final long newModificationStamp, final long newTimeStamp) throws IOException { throw new UnsupportedOperationException("getOutputStream is not implemented"); } + @Override @Nullable public VirtualFile getParent() { throw new UnsupportedOperationException("getParent is not implemented"); } + @Override + @NotNull public String getPath() { throw new UnsupportedOperationException("getPath is not implemented"); } + @Override public long getTimeStamp() { throw new UnsupportedOperationException("getTimeStamp is not implemented"); } + @Override @NotNull public String getUrl() { throw new UnsupportedOperationException("getUrl is not implemented"); } + @Override public boolean isDirectory() { throw new UnsupportedOperationException("isDirectory is not implemented"); } + @Override public boolean isValid() { throw new UnsupportedOperationException("isValid is not implemented"); } + @Override public boolean isWritable() { throw new UnsupportedOperationException("isWritable is not implemented"); } + @Override public void refresh(final boolean asynchronous, final boolean recursive, final Runnable postRunnable) { throw new UnsupportedOperationException("refresh is not implemented"); } diff --git a/platform/platform-api/src/com/intellij/openapi/wm/IdeGlassPaneUtil.java b/platform/platform-api/src/com/intellij/openapi/wm/IdeGlassPaneUtil.java index 0c76911b6821..67375287e7b2 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/IdeGlassPaneUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/IdeGlassPaneUtil.java @@ -16,11 +16,12 @@ package com.intellij.openapi.wm; -import com.intellij.openapi.ui.Painter; import com.intellij.openapi.Disposable; +import com.intellij.openapi.ui.Painter; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Disposer; -import com.intellij.util.ui.update.UiNotifyConnector; import com.intellij.util.ui.update.Activatable; +import com.intellij.util.ui.update.UiNotifyConnector; import javax.swing.*; import java.awt.*; @@ -69,6 +70,9 @@ public class IdeGlassPaneUtil { public static boolean canBePreprocessed(MouseEvent e) { Component c = SwingUtilities.getDeepestComponentAt(e.getComponent(), e.getX(), e.getY()); + if (JBPopupFactory.getInstance().getParentBalloonFor(c) != null) { + return false; + } if (c instanceof IdeGlassPane.TopComponent) { return ((IdeGlassPane.TopComponent)c).canBePreprocessed(e); diff --git a/platform/platform-api/src/com/intellij/util/Alarm.java b/platform/platform-api/src/com/intellij/util/Alarm.java index 269b81b630c3..60d32332e4de 100644 --- a/platform/platform-api/src/com/intellij/util/Alarm.java +++ b/platform/platform-api/src/com/intellij/util/Alarm.java @@ -69,6 +69,10 @@ public class Alarm implements Disposable { } } + public void checkDisposed() { + LOG.assertTrue(!myDisposed, "Already disposed"); + } + public enum ThreadToUse { SWING_THREAD, SHARED_THREAD, @@ -158,7 +162,7 @@ public class Alarm implements Disposable { protected void _addRequest(@NotNull Runnable request, long delayMillis, ModalityState modalityState) { synchronized (LOCK) { - LOG.assertTrue(!myDisposed, "Already disposed"); + checkDisposed(); final Request requestToSchedule = new Request(request, modalityState, delayMillis); if (myActivationComponent == null || myActivationComponent.isShowing()) { diff --git a/platform/platform-api/src/com/intellij/util/ui/Animator.java b/platform/platform-api/src/com/intellij/util/ui/Animator.java index a7d9301a791f..9b0256012fd3 100644 --- a/platform/platform-api/src/com/intellij/util/ui/Animator.java +++ b/platform/platform-api/src/com/intellij/util/ui/Animator.java @@ -131,7 +131,10 @@ public abstract class Animator implements Disposable { public void resume() { final Application app = ApplicationManager.getApplication(); - if (app == null || app.isUnitTestMode()) return; + if (app == null || app.isUnitTestMode()) { + animationDone(); + return; + } if (myCycleDuration == 0) { myCurrentFrame = myTotalFrames - 1; diff --git a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java index 97ecd972b350..d9a1ba7a4e29 100644 --- a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java +++ b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java @@ -787,9 +787,9 @@ public final class TreeUtil { if (rowCount == oldRowCount) break; oldRowCount = rowCount; for (int i = 0; i < rowCount; i++) { - tree.expandRow(i); + tree.expandRow(i); + } } - } while (true); } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java index caecb4c31d7d..c4c8c8f7d8c7 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java @@ -104,7 +104,7 @@ public class HintManagerImpl extends HintManager implements Disposable { myAnActionListener = new MyAnActionListener(); actionManagerEx.addAnActionListener(myAnActionListener); - myCaretMoveListener = new CaretListener() { + myCaretMoveListener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { hideHints(HIDE_BY_ANY_KEY, false, false); @@ -131,6 +131,7 @@ public class HintManagerImpl extends HintManager implements Disposable { myEditorFocusListener = new FocusAdapter() { @Override public void focusLost(final FocusEvent e) { + if (UIUtil.isFocusProxy(e.getOppositeComponent())) return; myHideAlarm.addRequest(new Runnable() { @Override public void run() { diff --git a/platform/platform-impl/src/com/intellij/designer/model/Property.java b/platform/platform-impl/src/com/intellij/designer/model/Property.java index b44b5991edf1..9f902c8f864e 100644 --- a/platform/platform-impl/src/com/intellij/designer/model/Property.java +++ b/platform/platform-impl/src/com/intellij/designer/model/Property.java @@ -120,6 +120,10 @@ public abstract class Property<T extends PropertiesContainer> { return false; } + public boolean closeEditorDuringRefresh() { + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// // // Presentation diff --git a/platform/platform-impl/src/com/intellij/designer/propertyTable/PropertyTable.java b/platform/platform-impl/src/com/intellij/designer/propertyTable/PropertyTable.java index 9ea80470d7f1..e8deef934e8e 100644 --- a/platform/platform-impl/src/com/intellij/designer/propertyTable/PropertyTable.java +++ b/platform/platform-impl/src/com/intellij/designer/propertyTable/PropertyTable.java @@ -848,7 +848,7 @@ public abstract class PropertyTable extends JBTable { if (isSetValue) { if (property.needRefreshPropertyList() || needRefresh[0]) { - update(myContainers, null, false); + update(myContainers, null, property.closeEditorDuringRefresh()); } else { myModel.fireTableRowsUpdated(row, row); @@ -1113,7 +1113,7 @@ public abstract class PropertyTable extends JBTable { } if (setValueAtRow(editingRow, value)) { - if (!continueEditing) { + if (!continueEditing && editingRow != -1) { PropertyEditor editor = myProperties.get(editingRow).getEditor(); editor.removePropertyEditorListener(myPropertyEditorListener); removeEditor(); diff --git a/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java b/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java index cf959586f60b..9933dd59f46a 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java +++ b/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java @@ -227,6 +227,9 @@ public final class ScriptRunnerUtil { long millisTimeout, @Nullable String commandLine) { if (processHandler.isProcessTerminated()) { + if (commandLine == null && processHandler instanceof BaseOSProcessHandler) { + commandLine = ((BaseOSProcessHandler) processHandler).getCommandLine(); + } LOG.warn("Process '" + commandLine + "' is already terminated!"); return; } diff --git a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java index 6e6c052d0e3b..39886a2eb20a 100644 --- a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java +++ b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.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. @@ -33,6 +33,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.WindowManager; import com.intellij.ui.HyperlinkAdapter; import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.SystemProperties; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.PropertyKey; @@ -119,6 +120,10 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter { } private static void startDiskSpaceMonitoring() { + if (SystemProperties.getBooleanProperty("idea.no.system.path.space.monitoring", false)) { + return; + } + final File file = new File(PathManager.getSystemPath()); final AtomicBoolean reported = new AtomicBoolean(); final ThreadLocal<Future<Long>> ourFreeSpaceCalculation = new ThreadLocal<Future<Long>>(); diff --git a/platform/platform-impl/src/com/intellij/ide/dnd/FileCopyPasteUtil.java b/platform/platform-impl/src/com/intellij/ide/dnd/FileCopyPasteUtil.java index cecde708b61b..dca050bcd31f 100644 --- a/platform/platform-impl/src/com/intellij/ide/dnd/FileCopyPasteUtil.java +++ b/platform/platform-impl/src/com/intellij/ide/dnd/FileCopyPasteUtil.java @@ -51,8 +51,8 @@ public class FileCopyPasteUtil { public static DataFlavor createDataFlavor(@NotNull final String mimeType, @Nullable final Class<?> klass, final boolean register) { try { - final String typeString = klass != null ? mimeType + ";class=" + klass.getName() : mimeType; - final DataFlavor flavor = new DataFlavor(typeString); + final DataFlavor flavor = + klass != null ? new DataFlavor(mimeType + ";class=" + klass.getName(), null, klass.getClassLoader()) : new DataFlavor(mimeType); if (register) { final FlavorMap map = SystemFlavorMap.getDefaultFlavorMap(); diff --git a/platform/platform-impl/src/com/intellij/ide/impl/SelectInEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/impl/SelectInEditorManagerImpl.java index 6c7efde06915..2eebf984707a 100644 --- a/platform/platform-impl/src/com/intellij/ide/impl/SelectInEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/impl/SelectInEditorManagerImpl.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. @@ -143,6 +143,14 @@ public class SelectInEditorManagerImpl extends SelectInEditorManager implements releaseAll(); } + @Override + public void caretAdded(CaretEvent e) { + } + + @Override + public void caretRemoved(CaretEvent e) { + } + private void releaseAll() { if (mySegmentHighlighter != null && myEditor != null){ mySegmentHighlighter.dispose(); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHeaderPanel.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHeaderPanel.java index e6664c0845e6..285efb41f1a2 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHeaderPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHeaderPanel.java @@ -83,6 +83,7 @@ public class PluginHeaderPanel { //data myName.setText("<html><body>" + plugin.getName() + "</body></html>"); myCategory.setText(plugin.getCategory() == null ? "UNKNOWN" : plugin.getCategory().toUpperCase()); + final boolean hasNewerVersion = InstalledPluginsTableModel.hasNewerVersion(plugin.getPluginId()); if (plugin instanceof PluginNode) { final PluginNode node = (PluginNode)plugin; @@ -93,7 +94,7 @@ public class PluginHeaderPanel { myUpdated.setText("Updated " + DateFormatUtil.formatDate(node.getDate())); switch (node.getStatus()) { case PluginNode.STATUS_INSTALLED: - myActionId = InstalledPluginsTableModel.hasNewerVersion(plugin.getPluginId()) ? ACTION_ID.UPDATE : ACTION_ID.UNINSTALL; + myActionId = hasNewerVersion ? ACTION_ID.UPDATE : ACTION_ID.UNINSTALL; break; case PluginNode.STATUS_DOWNLOADED: myActionId = ACTION_ID.RESTART; @@ -114,10 +115,10 @@ public class PluginHeaderPanel { final String version = plugin.getVersion(); myVersion.setText("Version: " + (version == null ? "N/A" : version)); myUpdated.setVisible(false); - if (!plugin.isBundled()) { + if (!plugin.isBundled() || hasNewerVersion) { if (((IdeaPluginDescriptorImpl)plugin).isDeleted()) { myActionId = ACTION_ID.RESTART; - } else if (InstalledPluginsTableModel.hasNewerVersion(plugin.getPluginId())) { + } else if (hasNewerVersion) { myActionId = ACTION_ID.UPDATE; } else { myActionId = ACTION_ID.UNINSTALL; diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginsTableRenderer.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginsTableRenderer.java index 174ca5a3f372..3b2ac0553fba 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginsTableRenderer.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginsTableRenderer.java @@ -17,6 +17,7 @@ package com.intellij.ide.plugins; import com.intellij.icons.AllIcons; import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vcs.FileStatus; import com.intellij.ui.Gray; @@ -93,6 +94,11 @@ public class PluginsTableRenderer extends DefaultTableCellRenderer { } if (myPluginDescriptor.isBundled()) { myCategory.setText(myCategory.getText() + "[Bundled]"); + myStatus.setIcon(AllIcons.Nodes.PluginJB); + } + final String vendor = myPluginDescriptor.getVendor(); + if (vendor != null && vendor.toLowerCase().contains("jetbrains")) { + myStatus.setIcon(AllIcons.Nodes.PluginJB); } myPanel.setBackground(bg); @@ -120,6 +126,7 @@ public class PluginsTableRenderer extends DefaultTableCellRenderer { if (!isSelected) myName.setForeground(FileStatus.ADDED.getColor()); //todo[kb] set proper icon //myStatus.setText("[Downloaded]"); + myStatus.setIcon(AllIcons.Nodes.PluginRestart); //myPanel.setToolTipText(IdeBundle.message("plugin.download.status.tooltip")); //myStatus.setBorder(BorderFactory.createEmptyBorder(0, LEFT_MARGIN, 0, 0)); } @@ -136,6 +143,16 @@ public class PluginsTableRenderer extends DefaultTableCellRenderer { //todo[kb] set proper icon //myStatus.setText("v." + pluginNode.getInstalledVersion() + (hasNewerVersion ? (" -> " + pluginNode.getVersion()) : "")); } + + if (InstalledPluginsTableModel.hasNewerVersion(myPluginDescriptor.getPluginId())) { + myStatus.setIcon(AllIcons.Nodes.Pluginobsolete); + if (!isSelected) { + myName.setForeground(JBColor.RED); + } + } + if (!myPluginDescriptor.isEnabled()) { + myStatus.setIcon(IconLoader.getDisabledIcon(myStatus.getIcon())); + } } return myPanel; diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java index f858002f0743..818466ba3153 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java @@ -273,6 +273,10 @@ public class DarculaLaf extends BasicLookAndFeel { } protected Object parseValue(String key, @NotNull String value) { + if ("null".equals(value)) { + return null; + } + if (key.endsWith("Insets")) { final List<String> numbers = StringUtil.split(value, ","); return new InsetsUIResource(Integer.parseInt(numbers.get(0)), diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties index b975ff8a666d..1f29a08d8612 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties @@ -122,6 +122,9 @@ Button.darcula.selection.color2=233143 Button.darcula.selectedButtonForeground=bbbbbb Button.darcula.disabledText.shadow=00000000 +ToggleButton.border=com.intellij.ide.ui.laf.darcula.ui.DarculaButtonPainter +ToggleButtonUI=com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI + MenuItem.acceleratorForeground=eeeeee PopupMenu.translucentBackground=3c3f41 diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java index f4fbc75dd935..8deb957d21f1 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java @@ -50,7 +50,7 @@ public class DarculaButtonUI extends BasicButtonUI { final Insets ins = border.getBorderInsets(c); final int yOff = (ins.top + ins.bottom) / 4; if (!square) { - if (((JButton)c).isDefaultButton()) { + if (c instanceof JButton && ((JButton)c).isDefaultButton()) { ((Graphics2D)g).setPaint(UIUtil.getGradientPaint(0, 0, getSelectedButtonColor1(), 0, c.getHeight(), getSelectedButtonColor2())); } else { @@ -100,7 +100,7 @@ public class DarculaButtonUI extends BasicButtonUI { @Override public void update(Graphics g, JComponent c) { super.update(g, c); - if (((JButton)c).isDefaultButton() && !SystemInfo.isMac) { + if (c instanceof JButton && ((JButton)c).isDefaultButton() && !SystemInfo.isMac) { if (!c.getFont().isBold()) { c.setFont(c.getFont().deriveFont(Font.BOLD)); } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaToggleButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaToggleButtonUI.java new file mode 100644 index 000000000000..b35ac61ca8c1 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaToggleButtonUI.java @@ -0,0 +1,26 @@ +/* + * 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. + * 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.ide.ui.laf.darcula.ui; + +import javax.swing.*; +import javax.swing.plaf.ComponentUI; + +public class DarculaToggleButtonUI extends DarculaButtonUI { + @SuppressWarnings("MethodOverridesStaticMethodOfSuperclass") + public static ComponentUI createUI(JComponent c) { + return new DarculaToggleButtonUI(); + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties index 116adfe47398..cd99cb129fd0 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties @@ -130,6 +130,9 @@ Button.darcula.selection.color2=3a6bc6 Button.darcula.selectedButtonForeground=f0f0f0 Button.darcula.disabledText.shadow=ffffff +ToggleButton.border=com.intellij.ide.ui.laf.darcula.ui.DarculaButtonPainter +ToggleButtonUI=com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI + MenuItem.acceleratorForeground=505050 PopupMenu.translucentBackground=e8e8e8 diff --git a/platform/platform-impl/src/com/intellij/internal/ToggleDumbModeAction.java b/platform/platform-impl/src/com/intellij/internal/ToggleDumbModeAction.java index 14e6d9265f07..855c898ae207 100644 --- a/platform/platform-impl/src/com/intellij/internal/ToggleDumbModeAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ToggleDumbModeAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import com.intellij.openapi.project.DumbServiceImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.TimeoutUtil; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -50,14 +51,15 @@ public class ToggleDumbModeAction extends AnAction implements DumbAware { return 0; } - public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { + @NotNull + public VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator) { while (myDumb) { TimeoutUtil.sleep(100); } return VirtualFile.EMPTY_ARRAY; } - public void processFile(FileContent fileContent) { + public void processFile(@NotNull FileContent fileContent) { } public void updatingDone() { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/DiffPanelComboBoxAction.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/DiffPanelComboBoxAction.java new file mode 100644 index 000000000000..b3ef9595782f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/DiffPanelComboBoxAction.java @@ -0,0 +1,94 @@ +package com.intellij.openapi.diff.actions; + +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.diff.DiffBundle; +import com.intellij.openapi.diff.ex.DiffPanelEx; +import com.intellij.openapi.diff.impl.DiffPanelImpl; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.util.containers.HashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.Map; + +public abstract class DiffPanelComboBoxAction<T> extends ComboBoxAction implements DumbAware { + @NotNull private final Map<T, AnAction> myActions = new HashMap<T, AnAction>(); + @NotNull private final T[] myActionOrder; + + protected DiffPanelComboBoxAction(@NotNull T[] actionOrder) { + myActionOrder = actionOrder; + } + + @NotNull + protected abstract String getActionName(); + + @NotNull + protected abstract T getCurrentOption(@NotNull DiffPanelEx diffPanel); + + @Nullable + private static DiffPanelEx getDiffPanel(@NotNull DataContext context) { + return DiffPanelImpl.fromDataContext(context); + } + + protected void addAction(T key, @NotNull AnAction action) { + myActions.put(key, action); + } + + @Override + public JComponent createCustomComponent(final Presentation presentation) { + JPanel panel = new JPanel(new BorderLayout()); + final JLabel label = new JLabel(getActionName()); + label.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); + panel.add(label, BorderLayout.WEST); + panel.add(super.createCustomComponent(presentation), BorderLayout.CENTER); + return panel; + } + + @NotNull + @Override + protected DefaultActionGroup createPopupActionGroup(JComponent button) { + DefaultActionGroup actionGroup = new DefaultActionGroup(); + for (T option : myActionOrder) { + actionGroup.add(myActions.get(option)); + } + return actionGroup; + } + + @Override + public void update(AnActionEvent e) { + super.update(e); + Presentation presentation = e.getPresentation(); + DiffPanelEx diffPanel = getDiffPanel(e.getDataContext()); + if (diffPanel != null && diffPanel.getComponent().isDisplayable()) { + AnAction action = myActions.get(getCurrentOption(diffPanel)); + Presentation templatePresentation = action.getTemplatePresentation(); + presentation.setIcon(templatePresentation.getIcon()); + presentation.setText(templatePresentation.getText()); + presentation.setEnabled(true); + } + else { + presentation.setIcon(null); + presentation.setText(DiffBundle.message("diff.panel.combo.box.action.not.available.action.name")); + presentation.setEnabled(false); + } + } + + protected static abstract class DiffPanelAction extends DumbAwareAction { + public DiffPanelAction(@NotNull String text) { + super(text); + } + + public void actionPerformed(AnActionEvent e) { + final DiffPanelEx diffPanel = getDiffPanel(e.getDataContext()); + if (diffPanel != null) { + perform(diffPanel); + } + } + + protected abstract void perform(@NotNull DiffPanelEx diffPanel); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/HighlightModeAction.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/HighlightModeAction.java index 8ae6fa277738..65f5eb346120 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/actions/HighlightModeAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/HighlightModeAction.java @@ -15,89 +15,48 @@ */ package com.intellij.openapi.diff.actions; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.diff.ex.DiffPanelEx; -import com.intellij.openapi.diff.impl.DiffPanelImpl; import com.intellij.openapi.diff.impl.processing.HighlightMode; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.*; -import java.util.Map; - -public class HighlightModeAction extends ComboBoxAction implements DumbAware { - private final Map<HighlightMode, AnAction> myActions = new HashMap<HighlightMode, AnAction>(); - private static final HighlightMode[] ourActionOrder = - new HighlightMode[]{HighlightMode.BY_WORD, HighlightMode.BY_LINE, HighlightMode.NO_HIGHLIGHTING}; +public class HighlightModeAction extends DiffPanelComboBoxAction<HighlightMode> { + private static final HighlightMode[] ourActionOrder = new HighlightMode[]{ + HighlightMode.BY_WORD, + HighlightMode.BY_LINE, + HighlightMode.NO_HIGHLIGHTING + }; public HighlightModeAction() { - myActions.put(HighlightMode.BY_WORD, - new SetHighlightModeAction(DiffBundle.message("diff.acton.highlight.mode.action.by.word"), HighlightMode.BY_WORD)); - myActions.put(HighlightMode.BY_LINE, - new SetHighlightModeAction(DiffBundle.message("diff.acton.highlight.mode.action.by.line"), HighlightMode.BY_LINE)); - myActions.put(HighlightMode.NO_HIGHLIGHTING, - new SetHighlightModeAction(DiffBundle.message("diff.acton.highlight.mode.action.no.highlighting"), - HighlightMode.NO_HIGHLIGHTING)); + super(ourActionOrder); + addAction(HighlightMode.BY_WORD, new HighlightingModeAction(DiffBundle.message("diff.acton.highlight.mode.action.by.word"), HighlightMode.BY_WORD)); + addAction(HighlightMode.BY_LINE, new HighlightingModeAction(DiffBundle.message("diff.acton.highlight.mode.action.by.line"), HighlightMode.BY_LINE)); + addAction(HighlightMode.NO_HIGHLIGHTING, new HighlightingModeAction(DiffBundle.message("diff.acton.highlight.mode.action.no.highlighting"), HighlightMode.NO_HIGHLIGHTING)); } + @NotNull @Override - public JComponent createCustomComponent(final Presentation presentation) { - JPanel panel = new JPanel(new BorderLayout()); - final JLabel label = new JLabel(DiffBundle.message("diff.acton.highlight.mode.action.name")); - label.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); - panel.add(label, BorderLayout.WEST); - panel.add(super.createCustomComponent(presentation), BorderLayout.CENTER); - return panel; + protected String getActionName() { + return DiffBundle.message("diff.acton.highlight.mode.action.name"); } @NotNull - protected DefaultActionGroup createPopupActionGroup(JComponent button) { - DefaultActionGroup actionGroup = new DefaultActionGroup(); - for (HighlightMode comparisonPolicy : ourActionOrder) { - actionGroup.add(myActions.get(comparisonPolicy)); - } - return actionGroup; - } - - public void update(AnActionEvent e) { - super.update(e); - Presentation presentation = e.getPresentation(); - DiffPanelEx diffPanel = DiffPanelImpl.fromDataContext(e.getDataContext()); - if (diffPanel != null && diffPanel.getComponent().isDisplayable()) { - AnAction action = myActions.get(diffPanel.getHighlightMode()); - Presentation templatePresentation = action.getTemplatePresentation(); - presentation.setIcon(templatePresentation.getIcon()); - presentation.setText(templatePresentation.getText()); - presentation.setEnabled(true); - } - else { - presentation.setIcon(null); - presentation.setText(DiffBundle.message("diff.acton.highlight.mode.not.available.action.name")); - presentation.setEnabled(false); - } + @Override + protected HighlightMode getCurrentOption(@NotNull DiffPanelEx diffPanel) { + return diffPanel.getHighlightMode(); } - private static class SetHighlightModeAction extends DumbAwareAction { + private static class HighlightingModeAction extends DiffPanelAction { private final HighlightMode myHighlightMode; - public SetHighlightModeAction(String text, HighlightMode mode) { + public HighlightingModeAction(String text, HighlightMode highlightMode) { super(text); - myHighlightMode = mode; + myHighlightMode = highlightMode; } - public void actionPerformed(AnActionEvent e) { - final DiffPanelImpl diffPanel = DiffPanelImpl.fromDataContext(e.getDataContext()); - if (diffPanel != null) { - diffPanel.setHighlightMode(myHighlightMode); - } + @Override + protected void perform(@NotNull DiffPanelEx diffPanel) { + diffPanel.setHighlightMode(myHighlightMode); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/IgnoreWhiteSpacesAction.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/IgnoreWhiteSpacesAction.java index 930db0e4f337..a46d8b1516c7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/actions/IgnoreWhiteSpacesAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/IgnoreWhiteSpacesAction.java @@ -15,74 +15,38 @@ */ package com.intellij.openapi.diff.actions; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.diff.ex.DiffPanelEx; import com.intellij.openapi.diff.impl.ComparisonPolicy; -import com.intellij.openapi.diff.impl.DiffPanelImpl; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.*; -import java.util.Map; - -public class IgnoreWhiteSpacesAction extends ComboBoxAction implements DumbAware { - private final Map<ComparisonPolicy, AnAction> myActions = new HashMap<ComparisonPolicy, AnAction>(); +public class IgnoreWhiteSpacesAction extends DiffPanelComboBoxAction<ComparisonPolicy> { private static final ComparisonPolicy[] ourActionOrder = new ComparisonPolicy[]{ ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_SPACE, - ComparisonPolicy.IGNORE_SPACE}; + ComparisonPolicy.IGNORE_SPACE + }; public IgnoreWhiteSpacesAction() { - myActions.put(ComparisonPolicy.DEFAULT, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.do.not.ignore"), ComparisonPolicy.DEFAULT)); - myActions.put(ComparisonPolicy.TRIM_SPACE, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.leading.and.trailing"), ComparisonPolicy.TRIM_SPACE)); - myActions.put(ComparisonPolicy.IGNORE_SPACE, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.all"), ComparisonPolicy.IGNORE_SPACE)); + super(ourActionOrder); + addAction(ComparisonPolicy.DEFAULT, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.do.not.ignore"), ComparisonPolicy.DEFAULT)); + addAction(ComparisonPolicy.TRIM_SPACE, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.leading.and.trailing"), ComparisonPolicy.TRIM_SPACE)); + addAction(ComparisonPolicy.IGNORE_SPACE, new IgnoringPolicyAction(DiffBundle.message("diff.acton.ignore.whitespace.policy.all"), ComparisonPolicy.IGNORE_SPACE)); } + @NotNull @Override - public JComponent createCustomComponent(final Presentation presentation) { - JPanel panel = new JPanel(new BorderLayout()); - final JLabel label = new JLabel(DiffBundle.message("ignore.whitespace.acton.name")); - label.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); - panel.add(label, BorderLayout.WEST); - panel.add(super.createCustomComponent(presentation), BorderLayout.CENTER); - return panel; + protected String getActionName() { + return DiffBundle.message("ignore.whitespace.acton.name"); } @NotNull - protected DefaultActionGroup createPopupActionGroup(JComponent button) { - DefaultActionGroup actionGroup = new DefaultActionGroup(); - for (ComparisonPolicy comparisonPolicy : ourActionOrder) { - actionGroup.add(myActions.get(comparisonPolicy)); - } - return actionGroup; - } - - public void update(AnActionEvent e) { - super.update(e); - Presentation presentation = e.getPresentation(); - DiffPanelEx diffPanel = DiffPanelImpl.fromDataContext(e.getDataContext()); - if (diffPanel != null && diffPanel.getComponent().isDisplayable()) { - AnAction action = myActions.get(diffPanel.getComparisonPolicy()); - Presentation templatePresentation = action.getTemplatePresentation(); - presentation.setIcon(templatePresentation.getIcon()); - presentation.setText(templatePresentation.getText()); - presentation.setEnabled(true); - } else { - presentation.setIcon(null); - presentation.setText(DiffBundle.message("ignore.whitespace.action.not.available.action.name")); - presentation.setEnabled(false); - } + @Override + protected ComparisonPolicy getCurrentOption(@NotNull DiffPanelEx diffPanel) { + return diffPanel.getComparisonPolicy(); } - private static class IgnoringPolicyAction extends DumbAwareAction { + private static class IgnoringPolicyAction extends DiffPanelAction { private final ComparisonPolicy myPolicy; public IgnoringPolicyAction(String text, ComparisonPolicy policy) { @@ -90,11 +54,9 @@ public class IgnoreWhiteSpacesAction extends ComboBoxAction implements DumbAware myPolicy = policy; } - public void actionPerformed(AnActionEvent e) { - final DiffPanelImpl diffPanel = DiffPanelImpl.fromDataContext(e.getDataContext()); - if (diffPanel != null) { - diffPanel.setComparisonPolicy(myPolicy); - } + @Override + protected void perform(@NotNull DiffPanelEx diffPanel) { + diffPanel.setComparisonPolicy(myPolicy); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/CurrentLineMarker.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/CurrentLineMarker.java index 8d7559dc575d..515fc9df9936 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/CurrentLineMarker.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/CurrentLineMarker.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. @@ -64,4 +64,14 @@ public class CurrentLineMarker implements CaretListener { if (isHiden()) return; set(); } + + @Override + public void caretAdded(CaretEvent e) { + + } + + @Override + public void caretRemoved(CaretEvent e) { + + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java index a3715fdeaec4..1ee83be74224 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java @@ -19,11 +19,10 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.diff.DiffContent; import com.intellij.openapi.diff.DiffContentUtil; import com.intellij.openapi.diff.DiffViewer; -import com.intellij.openapi.diff.LineTokenizer; -import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.external.DiffManagerImpl; import com.intellij.openapi.diff.impl.fragments.Fragment; import com.intellij.openapi.diff.impl.fragments.LineFragment; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.impl.util.FocusDiffSide; import com.intellij.openapi.diff.impl.util.TextDiffType; import com.intellij.openapi.editor.Document; @@ -34,7 +33,6 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.FrameWrapper; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ImageLoader; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -47,7 +45,7 @@ public class DiffUtil { private DiffUtil() { } - public static void initDiffFrame(Project project, FrameWrapper frameWrapper, final DiffViewer diffPanel, final JComponent mainComponent) { + public static void initDiffFrame(Project project, @NotNull FrameWrapper frameWrapper, @NotNull final DiffViewer diffPanel, final JComponent mainComponent) { frameWrapper.setComponent(mainComponent); frameWrapper.setProject(project); frameWrapper.setImage(ImageLoader.loadFromResource("/diff/Diff.png")); @@ -56,15 +54,17 @@ public class DiffUtil { } @Nullable - public static FocusDiffSide getFocusDiffSide(DataContext dataContext) { + public static FocusDiffSide getFocusDiffSide(@NotNull DataContext dataContext) { return FocusDiffSide.DATA_KEY.getData(dataContext); } - public static String[] convertToLines(@NotNull String text) { - return new LineTokenizer(text).execute(); + @NotNull + public static DiffString[] convertToLines(@NotNull String text) { + return DiffString.create(text).tokenize(); } - public static FileType[] chooseContentTypes(DiffContent[] contents) { + @NotNull + public static FileType[] chooseContentTypes(@NotNull DiffContent[] contents) { FileType commonType = FileTypes.PLAIN_TEXT; for (DiffContent content : contents) { FileType contentType = content.getContentType(); @@ -78,7 +78,7 @@ public class DiffUtil { return result; } - public static boolean isWritable(DiffContent content) { + public static boolean isWritable(@NotNull DiffContent content) { Document document = content.getDocument(); return document != null && document.isWritable(); } @@ -92,7 +92,7 @@ public class DiffUtil { return editor; } - public static void drawBoldDottedFramingLines(Graphics2D g, int startX, int endX, int startY, int bottomY, Color color) { + public static void drawBoldDottedFramingLines(@NotNull Graphics2D g, int startX, int endX, int startY, int bottomY, @NotNull Color color) { UIUtil.drawBoldDottedLine(g, startX, endX, startY, null, color, false); UIUtil.drawBoldDottedLine(g, startX, endX, bottomY, null, color, false); } @@ -102,8 +102,9 @@ public class DiffUtil { UIUtil.drawLine(g, startX, y + 1, endX, y + 1, null, color); } - public static Color getFramingColor(@NotNull Color backgroundColor) { - return backgroundColor.darker(); + @Nullable + public static Color getFramingColor(@Nullable Color backgroundColor) { + return backgroundColor != null ? backgroundColor.darker() : null; } @NotNull diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java index d3b273fdaba9..7e395c1b4a9e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java @@ -137,7 +137,8 @@ public class FragmentedDiffPanelState extends DiffPanelState { //setDiffPolicy(diffPolicy); diffPolicy.setRanges(ranges); - return addMarkup(new TextCompareProcessor(myComparisonPolicy, diffPolicy).process(myAppender1.getText(), myAppender2.getText())); + return addMarkup( + new TextCompareProcessor(myComparisonPolicy, diffPolicy, myHighlightMode).process(myAppender1.getText(), myAppender2.getText())); } private BeforeAfter<Integer> lineStarts(int i) { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/PresetBlocksDiffPolicy.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/PresetBlocksDiffPolicy.java index db11ed063c7e..3fd7df130e45 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/PresetBlocksDiffPolicy.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/PresetBlocksDiffPolicy.java @@ -15,11 +15,14 @@ */ package com.intellij.openapi.diff.impl.highlighting; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.processing.DiffPolicy; import com.intellij.openapi.util.TextRange; import com.intellij.util.BeforeAfter; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; import java.util.ArrayList; import java.util.Arrays; @@ -33,19 +36,28 @@ import java.util.List; public class PresetBlocksDiffPolicy implements DiffPolicy { // fragment _start_ offsets private List<BeforeAfter<TextRange>> myRanges; - private final DiffPolicy myDelegate; + @NotNull private final DiffPolicy myDelegate; - public PresetBlocksDiffPolicy(DiffPolicy delegate) { + public PresetBlocksDiffPolicy(@NotNull DiffPolicy delegate) { myDelegate = delegate; } + @TestOnly + @NotNull @Override - public DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException { + public DiffFragment[] buildFragments(@NotNull String text1, @NotNull String text2) throws FilesTooBigForDiffException { + return buildFragments(DiffString.create(text1), DiffString.create(text2)); + } + + @NotNull + @Override + public DiffFragment[] buildFragments(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException { final List<DiffFragment> fragments = new ArrayList<DiffFragment>(); for (int i = 0; i < myRanges.size(); i++) { final BeforeAfter<TextRange> range = myRanges.get(i); - fragments.addAll(Arrays.asList(myDelegate.buildFragments(new String(text1.substring(range.getBefore().getStartOffset(), range.getBefore().getEndOffset())), - new String(text2.substring(range.getAfter().getStartOffset(), range.getAfter().getEndOffset()))))); + fragments.addAll(Arrays.asList(myDelegate.buildFragments( + text1.substring(range.getBefore().getStartOffset(), range.getBefore().getEndOffset()).copy(), + text2.substring(range.getAfter().getStartOffset(), range.getAfter().getEndOffset()).copy()))); } return fragments.toArray(new DiffFragment[fragments.size()]); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java index 14c235470347..d3e1dfd5a64a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java @@ -30,8 +30,8 @@ import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; +import java.util.List; public abstract class SimpleDiffPanelState implements Disposable { protected ComparisonPolicy myComparisonPolicy = ComparisonPolicy.DEFAULT; @@ -84,7 +84,7 @@ public abstract class SimpleDiffPanelState implements Disposable { public void dispose() { } - private LineBlocks addMarkup(final ArrayList<LineFragment> lines) { + private LineBlocks addMarkup(final List<LineFragment> lines) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { final FragmentHighlighterImpl fragmentHighlighter = new FragmentHighlighterImpl(myAppender1, myAppender2); @@ -114,12 +114,8 @@ public abstract class SimpleDiffPanelState implements Disposable { return LineBlocks.EMPTY; } - if (myHighlightMode == HighlightMode.NO_HIGHLIGHTING) { - return LineBlocks.fromLineFragments(Collections.<LineFragment>emptyList()); - } - - return addMarkup(new TextCompareProcessor(myComparisonPolicy, myDiffPolicy, myHighlightMode == HighlightMode.BY_WORD) - .process(myAppender1.getText(), myAppender2.getText())); + return addMarkup( + new TextCompareProcessor(myComparisonPolicy, myDiffPolicy, myHighlightMode).process(myAppender1.getText(), myAppender2.getText())); } public Project getProject() { return myProject; } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java index dc0e98e722fb..bbd8c929c203 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff.impl.incrementalMerge; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.DiffUtil; @@ -29,6 +30,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -108,12 +110,12 @@ public class ChangeList { private ArrayList<Change> buildChanges() throws FilesTooBigForDiffException { Document base = getDocument(FragmentSide.SIDE1); - String[] baseLines = DiffUtil.convertToLines(base.getText()); + DiffString[] baseLines = DiffUtil.convertToLines(base.getText()); Document version = getDocument(FragmentSide.SIDE2); - String[] versionLines = DiffUtil.convertToLines(version.getText()); + DiffString[] versionLines = DiffUtil.convertToLines(version.getText()); DiffFragment[] fragments = ComparisonPolicy.DEFAULT.buildDiffFragmentsFromLines(baseLines, versionLines); final ArrayList<Change> result = new ArrayList<Change>(); - new DiffFragmemntsEnumerator(fragments) { + new DiffFragmentsEnumerator(fragments) { protected void process(DiffFragment fragment) { if (fragment.isEqual()) return; Context context = getContext(); @@ -129,11 +131,11 @@ public class ChangeList { return myChanges.get(index); } - private abstract static class DiffFragmemntsEnumerator { + private abstract static class DiffFragmentsEnumerator { private final DiffFragment[] myFragments; private final Context myContext; - private DiffFragmemntsEnumerator(DiffFragment[] fragments) { + private DiffFragmentsEnumerator(DiffFragment[] fragments) { myContext = new Context(); myFragments = fragments; } @@ -142,8 +144,8 @@ public class ChangeList { for (DiffFragment fragment : myFragments) { myContext.myFragment = fragment; process(fragment); - String text1 = fragment.getText1(); - String text2 = fragment.getText2(); + DiffString text1 = fragment.getText1(); + DiffString text2 = fragment.getText2(); myContext.myStarts[0] += StringUtil.length(text1); myContext.myStarts[1] += StringUtil.length(text2); myContext.myLines[0] += countLines(text1); @@ -151,7 +153,7 @@ public class ChangeList { } } - private static int countLines(String text) { + private static int countLines(@Nullable DiffString text) { if (text == null) return 0; return StringUtil.countNewLines(text); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java index 2c1b1e267b15..d3a0b5a50d58 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java @@ -24,6 +24,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.diff.DiffContent; import com.intellij.openapi.diff.DiffRequest; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.incrementalMerge.ui.MergePanel2; @@ -149,8 +150,8 @@ public class MergeList implements UserDataHolder { @NotNull String baseText, @NotNull String rightText, @NotNull ContextLogger logger) throws FilesTooBigForDiffException { - DiffFragment[] leftFragments = DiffPolicy.DEFAULT_LINES.buildFragments(baseText, leftText); - DiffFragment[] rightFragments = DiffPolicy.DEFAULT_LINES.buildFragments(baseText, rightText); + DiffFragment[] leftFragments = DiffPolicy.DEFAULT_LINES.buildFragments(DiffString.create(baseText), DiffString.create(leftText)); + DiffFragment[] rightFragments = DiffPolicy.DEFAULT_LINES.buildFragments(DiffString.create(baseText), DiffString.create(rightText)); int[] leftOffsets = {0, 0}; int[] rightOffsets = {0, 0}; int leftIndex = 0; @@ -188,7 +189,7 @@ public class MergeList implements UserDataHolder { leftOffsets[1] += versionLength; } - private static int getTextLength(@Nullable String text1) { + private static int getTextLength(@Nullable DiffString text1) { return text1 != null ? text1.length() : 0; } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/PreferWholeLines.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/PreferWholeLines.java index 2a6a01c10414..2d41620f6de2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/PreferWholeLines.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/PreferWholeLines.java @@ -18,35 +18,47 @@ package com.intellij.openapi.diff.impl.processing; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.util.text.StringUtil; class PreferWholeLines implements DiffCorrection { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.PreferWholeLines"); public static final DiffCorrection INSTANCE = new PreferWholeLines(); + public DiffFragment[] correct(DiffFragment[] fragments) { for (int i = 1; i < fragments.length - 1; i++) { DiffFragment fragment = fragments[i]; if (!fragment.isOneSide()) continue; DiffFragment nextFragment = fragments[i + 1]; FragmentSide side = FragmentSide.chooseSide(fragment); + + DiffString fragmentText = side.getText(fragment); + DiffString otherNextFragmentText = side.getOtherText(nextFragment); + DiffString nextFragmentText = side.getText(nextFragment); + if (nextFragment.isOneSide()) { - LOG.error("<" + side.getText(fragment) + "> <" + side.getOtherText(nextFragment) + ">"); + LOG.error("<" + fragmentText + "> <" + otherNextFragmentText + ">"); } - if (StringUtil.startsWithChar(side.getText(fragment), '\n') && - StringUtil.startsWithChar(side.getText(nextFragment), '\n') && - StringUtil.startsWithChar(side.getOtherText(nextFragment), '\n')) { + if (StringUtil.startsWithChar(fragmentText, '\n') && + StringUtil.startsWithChar(nextFragmentText, '\n') && + StringUtil.startsWithChar(otherNextFragmentText, '\n')) { + DiffFragment previous = fragments[i - 1]; - previous = side.createFragment(side.getText(previous) + "\n", - side.getOtherText(previous) + "\n", - previous.isModified()); + DiffString previousText = side.getText(previous); + DiffString otherPreciousText = side.getOtherText(previous); + + assert previous != null; + assert previousText != null; + assert otherPreciousText != null; + assert fragmentText != null; + assert nextFragmentText != null; + assert otherNextFragmentText != null; + + previous = side.createFragment(previousText.append('\n'), otherPreciousText.append('\n'), previous.isModified()); fragments[i - 1] = previous; - fragment = side.createFragment(side.getText(fragment).substring(1) + "\n", - side.getOtherText(fragment), - fragment.isModified()); + fragment = side.createFragment(fragmentText.substring(1).append('\n'), side.getOtherText(fragment), fragment.isModified()); fragments[i] = fragment; - nextFragment = side.createFragment(side.getText(nextFragment).substring(1), - side.getOtherText(nextFragment).substring(1), - nextFragment.isModified()); + nextFragment = side.createFragment(nextFragmentText.substring(1), otherNextFragmentText.substring(1), nextFragment.isModified()); fragments[i + 1] = nextFragment; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java index e527964a5c0d..1ae503e06d64 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java @@ -23,53 +23,59 @@ import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.LineBlockDivider; import com.intellij.openapi.diff.impl.highlighting.Util; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public class TextCompareProcessor { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.Processor"); - private final DiffPolicy myDiffPolicy; @NotNull private final ComparisonPolicy myComparisonPolicy; - private final boolean mySearchForSubFragments; + @NotNull private final DiffPolicy myDiffPolicy; + @NotNull private final HighlightMode myHighlightMode; public TextCompareProcessor(@NotNull ComparisonPolicy comparisonPolicy, - final DiffPolicy diffPolicy, - boolean searchForSubFragments) { + @NotNull DiffPolicy diffPolicy, + @NotNull HighlightMode highlightMode) { myComparisonPolicy = comparisonPolicy; myDiffPolicy = diffPolicy; - mySearchForSubFragments = searchForSubFragments; - } - - public TextCompareProcessor(@NotNull ComparisonPolicy comparisonPolicy, final DiffPolicy diffPolicy) { - this(comparisonPolicy, diffPolicy, true); + myHighlightMode = highlightMode; } public TextCompareProcessor(@NotNull ComparisonPolicy comparisonPolicy) { - this(comparisonPolicy, DiffPolicy.LINES_WO_FORMATTING); + this(comparisonPolicy, DiffPolicy.LINES_WO_FORMATTING, HighlightMode.BY_WORD); } - public ArrayList<LineFragment> process(@Nullable String text1, @Nullable String text2) throws FilesTooBigForDiffException { + public List<LineFragment> process(@Nullable String text1, @Nullable String text2) throws FilesTooBigForDiffException { + if (myHighlightMode == HighlightMode.NO_HIGHLIGHTING) { + return Collections.emptyList(); + } + text1 = StringUtil.notNullize(text1); text2 = StringUtil.notNullize(text2); if (text1.isEmpty() || text2.isEmpty()) { return new DummyDiffFragmentsProcessor().process(text1, text2); } - DiffFragment[] woFormattingBlocks = myDiffPolicy.buildFragments(text1, text2); + DiffString diffText1 = DiffString.create(text1); + DiffString diffText2 = DiffString.create(text2); + + DiffFragment[] woFormattingBlocks = myDiffPolicy.buildFragments(diffText1, diffText2); DiffFragment[] step1lineFragments = new DiffCorrection.TrueLineBlocks(myComparisonPolicy).correctAndNormalize(woFormattingBlocks); ArrayList<LineFragment> lineBlocks = new DiffFragmentsProcessor().process(step1lineFragments); int badLinesCount = 0; - if (mySearchForSubFragments) { + if (myHighlightMode == HighlightMode.BY_WORD) { for (LineFragment lineBlock : lineBlocks) { if (lineBlock.isOneSide() || lineBlock.isEqual()) continue; try { - String subText1 = lineBlock.getText(text1, FragmentSide.SIDE1); - String subText2 = lineBlock.getText(text2, FragmentSide.SIDE2); + DiffString subText1 = lineBlock.getText(diffText1, FragmentSide.SIDE1); + DiffString subText2 = lineBlock.getText(diffText2, FragmentSide.SIDE2); ArrayList<LineFragment> subFragments = findSubFragments(subText1, subText2); lineBlock.setChildren(new ArrayList<Fragment>(subFragments)); lineBlock.adjustTypeFromChildrenTypes(); @@ -84,7 +90,7 @@ public class TextCompareProcessor { return lineBlocks; } - private ArrayList<LineFragment> findSubFragments(String text1, String text2) throws FilesTooBigForDiffException { + private ArrayList<LineFragment> findSubFragments(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException { DiffFragment[] fragments = new ByWord(myComparisonPolicy).buildFragments(text1, text2); fragments = DiffCorrection.ConnectSingleSideToChange.INSTANCE.correct(fragments); fragments = UniteSameType.INSTANCE.correct(fragments); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java index 33db73f3a8eb..6e6a60702595 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java @@ -23,6 +23,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.util.Comparing; import com.intellij.util.ui.GraphicsUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.awt.*; import java.awt.geom.CubicCurve2D; @@ -34,7 +36,7 @@ import java.util.ArrayList; */ public class DividerPolygon { - private final Color myColor; + @Nullable private final Color myColor; private final int myStart1; private final int myStart2; private final int myEnd1; @@ -43,7 +45,7 @@ public class DividerPolygon { public static final double CTRL_PROXIMITY_X = 0.3; - public DividerPolygon(int start1, int start2, int end1, int end2, Color color, boolean applied) { + public DividerPolygon(int start1, int start2, int end1, int end2, @Nullable Color color, boolean applied) { myApplied = applied; myStart1 = advance(start1); myStart2 = advance(start2); @@ -150,7 +152,9 @@ public class DividerPolygon { //g.setComposite(composite); } - public static ArrayList<DividerPolygon> createVisiblePolygons(EditingSides sides, FragmentSide left, int diffDividerPolygonsOffset) { + public static ArrayList<DividerPolygon> createVisiblePolygons(@NotNull EditingSides sides, + @NotNull FragmentSide left, + int diffDividerPolygonsOffset) { Editor editor1 = sides.getEditor(left); Editor editor2 = sides.getEditor(left.otherSide()); LineBlocks lineBlocks = sides.getLineBlocks(); @@ -174,7 +178,10 @@ public class DividerPolygon { return new FoldingTransformation(editor); } - private static DividerPolygon createPolygon(Transformation[] transformations, Trapezium trapezium, Color color, FragmentSide left, + private static DividerPolygon createPolygon(@NotNull Transformation[] transformations, + @NotNull Trapezium trapezium, + @Nullable Color color, + @NotNull FragmentSide left, int diffDividerPolygonsOffset, boolean applied) { Interval base1 = trapezium.getBase(left); Interval base2 = trapezium.getBase(left.otherSide()); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/SyncScrollSupport.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/SyncScrollSupport.java index e169a9c20e81..f6cd904c9503 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/SyncScrollSupport.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/SyncScrollSupport.java @@ -26,7 +26,7 @@ import com.intellij.openapi.editor.ScrollingModel; import com.intellij.openapi.editor.event.VisibleAreaEvent; import com.intellij.openapi.editor.event.VisibleAreaListener; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -35,7 +35,7 @@ import java.util.ArrayList; public class SyncScrollSupport implements Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.util.SyncScrollSupport"); private boolean myDuringVerticalScroll = false; - private final ArrayList<ScrollListener> myScrollers = new ArrayList<ScrollListener>(); + @NotNull private final ArrayList<ScrollListener> myScrollers = new ArrayList<ScrollListener>(); private boolean myEnabled = true; public void install(EditingSides[] sideContainers) { @@ -67,34 +67,34 @@ public class SyncScrollSupport implements Disposable { return myEnabled; } - private void install2(Editor[] editors, EditingSides[] sideContainers) { - addSlavesScroller(editors[0], new Pair<FragmentSide, EditingSides>(FragmentSide.SIDE1, sideContainers[0])); - addSlavesScroller(editors[1], new Pair<FragmentSide, EditingSides>(FragmentSide.SIDE2, sideContainers[0])); + private void install2(@NotNull Editor[] editors, @NotNull EditingSides[] sideContainers) { + addSlavesScroller(editors[0], new ScrollingContext(FragmentSide.SIDE1, sideContainers[0], FragmentSide.SIDE1)); + addSlavesScroller(editors[1], new ScrollingContext(FragmentSide.SIDE2, sideContainers[0], FragmentSide.SIDE2)); } - private void install3(Editor[] editors, EditingSides[] sideContainers) { + private void install3(@NotNull Editor[] editors, @NotNull EditingSides[] sideContainers) { addSlavesScroller(editors[0], - new Pair<FragmentSide, EditingSides>(FragmentSide.SIDE1, sideContainers[0]), - new Pair<FragmentSide, EditingSides>(FragmentSide.SIDE1, sideContainers[1])); + new ScrollingContext(FragmentSide.SIDE1, sideContainers[0], FragmentSide.SIDE2), + new ScrollingContext(FragmentSide.SIDE1, sideContainers[1], FragmentSide.SIDE1)); addSlavesScroller(editors[1], - new Pair<FragmentSide, EditingSides>(FragmentSide.SIDE2, sideContainers[0]), - new Pair<FragmentSide, EditingSides>(FragmentSide.SIDE1, sideContainers[1])); + new ScrollingContext(FragmentSide.SIDE2, sideContainers[0], FragmentSide.SIDE1), + new ScrollingContext(FragmentSide.SIDE1, sideContainers[1], FragmentSide.SIDE1)); addSlavesScroller(editors[2], - new Pair<FragmentSide, EditingSides>(FragmentSide.SIDE2, sideContainers[1]), - new Pair<FragmentSide, EditingSides>(FragmentSide.SIDE2, sideContainers[0])); + new ScrollingContext(FragmentSide.SIDE2, sideContainers[1], FragmentSide.SIDE2), + new ScrollingContext(FragmentSide.SIDE2, sideContainers[0], FragmentSide.SIDE1)); } - private void addSlavesScroller(Editor editor, Pair<FragmentSide, EditingSides>... contexts) { + private void addSlavesScroller(@NotNull Editor editor, @NotNull ScrollingContext... contexts) { ScrollListener scroller = new ScrollListener(contexts, editor); scroller.install(); myScrollers.add(scroller); } private class ScrollListener implements VisibleAreaListener, Disposable { - private Pair<FragmentSide, EditingSides>[] myScrollContexts; - private final Editor myEditor; + private ScrollingContext[] myScrollContexts; + @NotNull private final Editor myEditor; - public ScrollListener(Pair<FragmentSide, EditingSides>[] scrollContexts, Editor editor) { + public ScrollListener(@NotNull ScrollingContext[] scrollContexts, @NotNull Editor editor) { myScrollContexts = scrollContexts; myEditor = editor; } @@ -103,11 +103,13 @@ public class SyncScrollSupport implements Disposable { myEditor.getScrollingModel().addVisibleAreaListener(this); } + @Override public void dispose() { myEditor.getScrollingModel().removeVisibleAreaListener(this); myScrollContexts = null; } + @Override public void visibleAreaChanged(VisibleAreaEvent e) { if (!myEnabled || myDuringVerticalScroll) return; Rectangle newRectangle = e.getNewRectangle(); @@ -115,7 +117,7 @@ public class SyncScrollSupport implements Disposable { if (newRectangle == null || oldRectangle == null) return; myDuringVerticalScroll = true; try { - for (Pair<FragmentSide, EditingSides> context : myScrollContexts) { + for (ScrollingContext context : myScrollContexts) { syncVerticalScroll(context, newRectangle, oldRectangle); syncHorizontalScroll(context, newRectangle, oldRectangle); } @@ -124,11 +126,13 @@ public class SyncScrollSupport implements Disposable { } } - private static void syncHorizontalScroll(Pair<FragmentSide,EditingSides> context, Rectangle newRectangle, Rectangle oldRectangle) { + private static void syncHorizontalScroll(@NotNull ScrollingContext context, + @NotNull Rectangle newRectangle, + @NotNull Rectangle oldRectangle) { int newScrollOffset = newRectangle.x; if (newScrollOffset == oldRectangle.x) return; - EditingSides sidesContainer = context.getSecond(); - FragmentSide masterSide = context.getFirst(); + EditingSides sidesContainer = context.getSidesContainer(); + FragmentSide masterSide = context.getMasterSide(); Editor slaveEditor = sidesContainer.getEditor(masterSide.otherSide()); if (slaveEditor == null) return; @@ -138,10 +142,13 @@ public class SyncScrollSupport implements Disposable { scrollingModel.enableAnimation(); } - private static void syncVerticalScroll(Pair<FragmentSide,EditingSides> context, Rectangle newRectangle, Rectangle oldRectangle) { + private static void syncVerticalScroll(@NotNull ScrollingContext context, + @NotNull Rectangle newRectangle, + @NotNull Rectangle oldRectangle) { if (newRectangle.y == oldRectangle.y && newRectangle.height == oldRectangle.height) return; - EditingSides sidesContainer = context.getSecond(); - FragmentSide masterSide = context.getFirst(); + EditingSides sidesContainer = context.getSidesContainer(); + FragmentSide masterSide = context.getMasterSide(); + FragmentSide masterDiffSide = context.getMasterDiffSide(); Editor master = sidesContainer.getEditor(masterSide); Editor slave = sidesContainer.getEditor(masterSide.otherSide()); @@ -159,7 +166,7 @@ public class SyncScrollSupport implements Disposable { if (masterCenterLine > master.getDocument().getLineCount()) { masterCenterLine = master.getDocument().getLineCount(); } - int scrollToLine = sidesContainer.getLineBlocks().transform(masterSide, masterCenterLine) + 1; + int scrollToLine = sidesContainer.getLineBlocks().transform(masterDiffSide, masterCenterLine) + 1; int actualLine = scrollToLine - 1; @@ -179,18 +186,45 @@ public class SyncScrollSupport implements Disposable { } } - private static int getScrollOffset(final Editor editor) { + private static int getScrollOffset(@NotNull final Editor editor) { final JComponent header = editor.getHeaderComponent(); int headerOffset = header == null ? 0 : header.getHeight(); return editor.getScrollingModel().getVerticalScrollOffset() - headerOffset; } - public static void scrollEditor(Editor editor, int logicalLine) { + public static void scrollEditor(@NotNull Editor editor, int logicalLine) { editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(logicalLine, 0)); ScrollingModel scrollingModel = editor.getScrollingModel(); scrollingModel.disableAnimation(); scrollingModel.scrollToCaret(ScrollType.CENTER); scrollingModel.enableAnimation(); } + + private static class ScrollingContext { + @NotNull private final EditingSides mySidesContainer; + @NotNull private final FragmentSide myMasterSide; + @NotNull private final FragmentSide myMasterDiffSide; + + public ScrollingContext(@NotNull FragmentSide masterSide, @NotNull EditingSides sidesContainer, @NotNull FragmentSide masterDiffSide) { + mySidesContainer = sidesContainer; + myMasterSide = masterSide; + myMasterDiffSide = masterDiffSide; + } + + @NotNull + public EditingSides getSidesContainer() { + return mySidesContainer; + } + + @NotNull + public FragmentSide getMasterSide() { + return myMasterSide; + } + + @NotNull + public FragmentSide getMasterDiffSide() { + return myMasterDiffSide; + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutAction.java index 4fc378e566c6..dd54b1de2087 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutAction.java @@ -53,12 +53,7 @@ public class CutAction extends EditorAction { }); } editor.getSelectionModel().copySelectionToClipboard(); - editor.getCaretModel().runForEachCaret(new CaretAction() { - @Override - public void perform(Caret caret) { - EditorModificationUtil.deleteSelectedText(editor); - } - }); + EditorModificationUtil.deleteSelectedTextForAllCarets(editor); } } }
\ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EscapeAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EscapeAction.java index 16b66768d791..bc3b85bfce95 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EscapeAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EscapeAction.java @@ -50,7 +50,7 @@ public class EscapeAction extends EditorAction { public boolean isEnabled(Editor editor, DataContext dataContext) { SelectionModel selectionModel = editor.getSelectionModel(); CaretModel caretModel = editor.getCaretModel(); - return selectionModel.hasSelection() || selectionModel.hasBlockSelection() || caretModel.getAllCarets().size() > 1; + return selectionModel.hasSelection() || selectionModel.hasBlockSelection() || caretModel.getCaretCount() > 1; } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/MoveCaretLeftOrRightHandler.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/MoveCaretLeftOrRightHandler.java index 1883cb55387c..182884b25020 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/MoveCaretLeftOrRightHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/MoveCaretLeftOrRightHandler.java @@ -49,13 +49,19 @@ class MoveCaretLeftOrRightHandler extends EditorActionHandler { int start = selectionModel.getSelectionStart(); int end = selectionModel.getSelectionEnd(); int caretOffset = caretModel.getOffset(); + VisualPosition targetPosition = myDirection == Direction.RIGHT ? selectionModel.getSelectionEndPosition() : selectionModel.getSelectionStartPosition(); //int leftGuard = start + (myDirection == Direction.LEFT ? 1 : 0); //int rightGuard = end - (myDirection == Direction.RIGHT ? 1 : 0); //if (TextRange.from(leftGuard, rightGuard - leftGuard + 1).contains(caretModel.getOffset())) { // See IDEADEV-36957 if (start <= caretOffset && end >= caretOffset) { // See IDEADEV-36957 selectionModel.removeSelection(); - caretModel.moveToOffset(myDirection == Direction.RIGHT ? end : start); + if (caretModel.supportsMultipleCarets() && editor.isColumnMode() && targetPosition != null) { + caretModel.moveToVisualPosition(targetPosition); + } + else { + caretModel.moveToOffset(myDirection == Direction.RIGHT ? end : start); + } scrollingModel.scrollToCaret(ScrollType.RELATIVE); return; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java index 012410d34fe3..41a833b3bffb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java @@ -806,6 +806,15 @@ public final class EditorUtil { int line = y / editor.getLineHeight(); return line > 0 ? editor.visualToLogicalPosition(new VisualPosition(line, 0)).line : 0; } + + public static boolean isAtLineEnd(@NotNull Editor editor, int offset) { + Document document = editor.getDocument(); + if (offset < 0 || offset > document.getTextLength()) { + return false; + } + int line = document.getLineNumber(offset); + return offset == document.getLineEndOffset(line); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java index 1b79d356cfb6..f6f030c67ee8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java @@ -94,6 +94,10 @@ public class CaretImpl extends UserDataHolderBase implements Caret { private int startBefore; private int endBefore; boolean myUnknownDirection; + // offsets of selection start/end position relative to end of line - can be non-zero in column selection mode + // these are non-negative values, myStartVirtualOffset is always less or equal to myEndVirtualOffset + private int myStartVirtualOffset; + private int myEndVirtualOffset; CaretImpl(EditorImpl editor) { myEditor = editor; @@ -144,10 +148,18 @@ public class CaretImpl extends UserDataHolderBase implements Caret { if (marker.isValid()) { startAfter = marker.getStartOffset(); endAfter = marker.getEndOffset(); + if (myEndVirtualOffset > 0 && (!isVirtualSelectionEnabled() + || !EditorUtil.isAtLineEnd(myEditor, endAfter) + || myEditor.getDocument().getLineNumber(startAfter) != myEditor.getDocument().getLineNumber(endAfter))) { + myStartVirtualOffset = 0; + myEndVirtualOffset = 0; + } } else { startAfter = endAfter = getOffset(); marker.release(); + myStartVirtualOffset = 0; + myEndVirtualOffset = 0; mySelectionMarker = null; } @@ -235,7 +247,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret { myEditor.getCaretModel().doWithCaretMerging(new Runnable() { public void run() { SelectionModelImpl selectionModel = myEditor.getSelectionModel(); - final int leadSelectionOffset = selectionModel.getLeadSelectionOffset(); + final int leadSelectionOffset = getLeadSelectionOffset(); + final VisualPosition leadSelectionPosition = getLeadSelectionPosition(); LogicalPosition blockSelectionStart = selectionModel.hasBlockSelection() ? selectionModel.getBlockStart() : getLogicalPosition(); @@ -349,24 +362,43 @@ public class CaretImpl extends UserDataHolderBase implements Caret { } else { if (selectToDocumentStart) { - selectionModel.setSelection(leadSelectionOffset, 0); + if (myEditor.getCaretModel().supportsMultipleCarets()) { + setSelection(leadSelectionPosition, leadSelectionOffset, myEditor.offsetToVisualPosition(0), 0); + } + else { + setSelection(leadSelectionOffset, 0); + } } else if (pos.line >= myEditor.getVisibleLineCount()) { - if (leadSelectionOffset < document.getTextLength()) { - selectionModel.setSelection(leadSelectionOffset, document.getTextLength()); + int endOffset = document.getTextLength(); + if (leadSelectionOffset < endOffset) { + if (myEditor.getCaretModel().supportsMultipleCarets()) { + setSelection(leadSelectionPosition, leadSelectionOffset, myEditor.offsetToVisualPosition(endOffset), endOffset); + } + else { + setSelection(leadSelectionOffset, endOffset); + } } } else { int selectionStartToUse = leadSelectionOffset; - if (selectionModel.isUnknownDirection()) { - if (getOffset() > leadSelectionOffset) { - selectionStartToUse = Math.min(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); + VisualPosition selectionStartPositionToUse = leadSelectionPosition; + if (isUnknownDirection()) { + if (getOffset() > leadSelectionOffset ^ getSelectionStart() < getSelectionEnd()) { + selectionStartToUse = getSelectionEnd(); + selectionStartPositionToUse = getSelectionEndPosition(); } else { - selectionStartToUse = Math.max(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); + selectionStartToUse = getSelectionStart(); + selectionStartPositionToUse = getSelectionStartPosition(); } } - selectionModel.setSelection(selectionStartToUse, getVisualPosition(), getOffset()); + if (myEditor.getCaretModel().supportsMultipleCarets()) { + setSelection(selectionStartPositionToUse, selectionStartToUse, getVisualPosition(), getOffset()); + } + else { + setSelection(selectionStartToUse, getVisualPosition(), getOffset()); + } } } } @@ -933,22 +965,32 @@ public class CaretImpl extends UserDataHolderBase implements Caret { int lineShift = above ? -1 : 1; final CaretImpl clone = cloneWithoutSelection(); final int newSelectionStartOffset, newSelectionEndOffset; + final VisualPosition newSelectionStartPosition, newSelectionEndPosition; final boolean hasNewSelection; if (hasSelection()) { - LogicalPosition selectionStart = myEditor.offsetToLogicalPosition(getSelectionStart()); - LogicalPosition selectionEnd = myEditor.offsetToLogicalPosition(getSelectionEnd()); - LogicalPosition newSelectionStart = new LogicalPosition(selectionStart.line + lineShift, selectionStart.column); - LogicalPosition newSelectionEnd = new LogicalPosition(selectionEnd.line + lineShift, selectionEnd.column); - newSelectionStartOffset = getTruncatedOffset(newSelectionStart); - newSelectionEndOffset = getTruncatedOffset(newSelectionEnd); - hasNewSelection = newSelectionStartOffset != newSelectionEndOffset; + VisualPosition startPosition = getSelectionStartPosition(); + VisualPosition endPosition = getSelectionEndPosition(); + VisualPosition leadPosition = getLeadSelectionPosition(); + boolean leadIsStart = leadPosition.equals(startPosition); + boolean leadIsEnd = leadPosition.equals(endPosition); + LogicalPosition selectionStart = myEditor.visualToLogicalPosition(leadIsStart || leadIsEnd ? leadPosition : startPosition); + LogicalPosition selectionEnd = myEditor.visualToLogicalPosition(leadIsEnd ? startPosition : endPosition); + LogicalPosition newSelectionStart = truncate(new LogicalPosition(selectionStart.line + lineShift, selectionStart.column)); + LogicalPosition newSelectionEnd = truncate(new LogicalPosition(selectionEnd.line + lineShift, selectionEnd.column)); + newSelectionStartOffset = myEditor.logicalPositionToOffset(newSelectionStart); + newSelectionEndOffset = myEditor.logicalPositionToOffset(newSelectionEnd); + newSelectionStartPosition = myEditor.logicalToVisualPosition(newSelectionStart); + newSelectionEndPosition = myEditor.logicalToVisualPosition(newSelectionEnd); + hasNewSelection = !newSelectionStart.equals(newSelectionEnd); } else { newSelectionStartOffset = 0; newSelectionEndOffset = 0; + newSelectionStartPosition = null; + newSelectionEndPosition = null; hasNewSelection = false; } - LogicalPosition oldPosition = hasSelection() && !hasNewSelection ? myEditor.offsetToLogicalPosition(getSelectionStart()) : getLogicalPosition(); + LogicalPosition oldPosition = getLogicalPosition(); int newLine = oldPosition.line + lineShift; if (newLine < 0 || newLine >= myEditor.getDocument().getLineCount()) { Disposer.dispose(clone); @@ -956,11 +998,11 @@ public class CaretImpl extends UserDataHolderBase implements Caret { } clone.moveToLogicalPosition(new LogicalPosition(newLine, oldPosition.column), false, null, false); if (myEditor.getCaretModel().addCaret(clone)) { - if (hasSelection() && hasNewSelection) { + if (hasNewSelection) { myEditor.getCaretModel().doWithCaretMerging(new Runnable() { @Override public void run() { - clone.setSelection(Math.min(newSelectionStartOffset, newSelectionEndOffset), Math.max(newSelectionStartOffset, newSelectionEndOffset)); + clone.setSelection(newSelectionStartPosition, newSelectionStartOffset, newSelectionEndPosition, newSelectionEndOffset); } }); if (!clone.isValid()) { @@ -976,15 +1018,15 @@ public class CaretImpl extends UserDataHolderBase implements Caret { } } - private int getTruncatedOffset(LogicalPosition position) { + private LogicalPosition truncate(LogicalPosition position) { if (position.line < 0) { - return 0; + return new LogicalPosition(0, 0); } else if (position.line >= myEditor.getDocument().getLineCount()) { - return myEditor.getDocument().getTextLength(); + return myEditor.offsetToLogicalPosition(myEditor.getDocument().getTextLength()); } else { - return myEditor.logicalPositionToOffset(position); + return position; } } @@ -1029,18 +1071,21 @@ public class CaretImpl extends UserDataHolderBase implements Caret { @NotNull @Override public VisualPosition getSelectionStartPosition() { - VisualPosition defaultPosition = myEditor.offsetToVisualPosition(getSelectionStart()); - if (!hasSelection()) { - return defaultPosition; + validateContext(false); + VisualPosition position; + if (hasSelection() && mySelectionMarker != null) { + position = mySelectionMarker.getStartPosition(); + if (position == null) { + position = myEditor.offsetToVisualPosition(mySelectionMarker.getStartOffset()); + } } - - MyRangeMarker marker = mySelectionMarker; - if (marker == null) { - return defaultPosition; + else { + position = isVirtualSelectionEnabled() ? getVisualPosition() : myEditor.offsetToVisualPosition(getOffset()); } - - VisualPosition result = marker.getStartPosition(); - return result == null ? defaultPosition : result; + if (hasVirtualSelection()) { + position = new VisualPosition(position.line, position.column + myStartVirtualOffset); + } + return position; } @Override @@ -1058,25 +1103,29 @@ public class CaretImpl extends UserDataHolderBase implements Caret { @NotNull @Override public VisualPosition getSelectionEndPosition() { - VisualPosition defaultPosition = myEditor.offsetToVisualPosition(getSelectionEnd()); - if (!hasSelection()) { - return defaultPosition; + validateContext(false); + VisualPosition position; + if (hasSelection() && mySelectionMarker != null) { + position = mySelectionMarker.getEndPosition(); + if (position == null) { + position = myEditor.offsetToVisualPosition(mySelectionMarker.getEndOffset()); + } } - - MyRangeMarker marker = mySelectionMarker; - if (marker == null) { - return defaultPosition; + else { + position = isVirtualSelectionEnabled() ? getVisualPosition() : myEditor.offsetToVisualPosition(getOffset()); } - - VisualPosition result = marker.getEndPosition(); - return result == null ? defaultPosition : result; + if (hasVirtualSelection()) { + position = new VisualPosition(position.line, position.column + myEndVirtualOffset); + } + return position; } @Override public boolean hasSelection() { validateContext(false); MyRangeMarker marker = mySelectionMarker; - return marker != null && marker.isValid() && marker.getEndOffset() > marker.getStartOffset(); + return marker != null && marker.isValid() && (marker.getEndOffset() > marker.getStartOffset() + || isVirtualSelectionEnabled() && myEndVirtualOffset > myStartVirtualOffset); } @Override @@ -1162,10 +1211,12 @@ public class CaretImpl extends UserDataHolderBase implements Caret { } /* Normalize selection */ + boolean switchedOffsets = false; if (startOffset > endOffset) { int tmp = startOffset; startOffset = endOffset; endOffset = tmp; + switchedOffsets = true; } FoldingModelEx foldingModel = myEditor.getFoldingModel(); @@ -1200,6 +1251,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret { } marker = new MyRangeMarker((DocumentEx)doc, startOffset, endOffset); + myStartVirtualOffset = 0; + myEndVirtualOffset = 0; if (visualPositionAware) { if (endPosition.after(startPosition)) { marker.setStartPosition(startPosition); @@ -1211,6 +1264,17 @@ public class CaretImpl extends UserDataHolderBase implements Caret { marker.setEndPosition(startPosition); marker.setEndPositionIsLead(true); } + + if (isVirtualSelectionEnabled() && + myEditor.getDocument().getLineNumber(startOffset) == myEditor.getDocument().getLineNumber(endOffset)) { + int endLineColumn = myEditor.offsetToVisualPosition(endOffset).column; + int startDiff = + EditorUtil.isAtLineEnd(myEditor, switchedOffsets ? endOffset : startOffset) ? startPosition.column - endLineColumn : 0; + int endDiff = + EditorUtil.isAtLineEnd(myEditor, switchedOffsets ? startOffset : endOffset) ? endPosition.column - endLineColumn : 0; + myStartVirtualOffset = Math.max(0, Math.min(startDiff, endDiff)); + myEndVirtualOffset = Math.max(0, Math.max(startDiff, endDiff)); + } } mySelectionMarker = marker; @@ -1248,6 +1312,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret { int endOffset = marker.getEndOffset(); marker.release(); mySelectionMarker = null; + myStartVirtualOffset = 0; + myEndVirtualOffset = 0; myEditor.getSelectionModel().fireSelectionChanged(startOffset, endOffset, caretOffset, caretOffset); } } @@ -1293,17 +1359,36 @@ public class CaretImpl extends UserDataHolderBase implements Caret { public VisualPosition getLeadSelectionPosition() { MyRangeMarker marker = mySelectionMarker; VisualPosition caretPosition = getVisualPosition(); + if (isVirtualSelectionEnabled() && !hasSelection()) { + return caretPosition; + } if (marker == null) { return caretPosition; } if (marker.isEndPositionIsLead()) { VisualPosition result = marker.getEndPosition(); - return result == null ? getSelectionEndPosition() : result; + if (result == null) { + return getSelectionEndPosition(); + } + else { + if (hasVirtualSelection()) { + result = new VisualPosition(result.line, result.column + myEndVirtualOffset); + } + return result; + } } else { VisualPosition result = marker.getStartPosition(); - return result == null ? getSelectionStartPosition() : result; + if (result == null) { + return getSelectionStartPosition(); + } + else { + if (hasVirtualSelection()) { + result = new VisualPosition(result.line, result.column + myStartVirtualOffset); + } + return result; + } } } @@ -1367,6 +1452,16 @@ public class CaretImpl extends UserDataHolderBase implements Caret { } } + private boolean isVirtualSelectionEnabled() { + return myEditor.isColumnMode() && myEditor.getCaretModel().supportsMultipleCarets(); + } + + boolean hasVirtualSelection() { + validateContext(false); + MyRangeMarker marker = mySelectionMarker; + return marker != null && marker.isValid() && isVirtualSelectionEnabled() && myEndVirtualOffset > myStartVirtualOffset; + } + /** * Encapsulates information about target vertical range info - its <code>'y'</code> coordinate and height in pixels. */ diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java index 72de1c92bbab..ad9e08d4f7f5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java @@ -31,13 +31,11 @@ import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.event.CaretEvent; import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.MultipleCaretListener; import com.intellij.openapi.editor.ex.DocumentBulkUpdateListener; import com.intellij.openapi.editor.ex.PrioritizedDocumentListener; import com.intellij.openapi.editor.impl.event.DocumentEventImpl; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Segment; import com.intellij.openapi.util.registry.Registry; import com.intellij.util.EventDispatcher; import org.jetbrains.annotations.NotNull; @@ -48,8 +46,7 @@ import java.util.*; public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, Disposable { private final EditorImpl myEditor; - private final EventDispatcher<MultipleCaretListener> myCaretListeners = EventDispatcher.create(MultipleCaretListener.class); - private final Map<CaretListener, MultipleCaretListener> myListenerMap = new HashMap<CaretListener, MultipleCaretListener>(); + private final EventDispatcher<CaretListener> myCaretListeners = EventDispatcher.create(CaretListener.class); private final boolean mySupportsMultipleCarets = Registry.is("editor.allow.multiple.carets"); private TextAttributes myTextAttributes; @@ -202,38 +199,12 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, @Override public void addCaretListener(@NotNull final CaretListener listener) { - MultipleCaretListener newListener; - if (listener instanceof MultipleCaretListener) { - newListener = (MultipleCaretListener)listener; - } - else { - newListener = new MultipleCaretListener() { - @Override - public void caretAdded(CaretEvent e) { - - } - - @Override - public void caretRemoved(CaretEvent e) { - - } - - @Override - public void caretPositionChanged(CaretEvent e) { - listener.caretPositionChanged(e); - } - }; - } - myListenerMap.put(listener, newListener); - myCaretListeners.addListener(newListener); + myCaretListeners.addListener(listener); } @Override public void removeCaretListener(@NotNull CaretListener listener) { - MultipleCaretListener newListener = myListenerMap.remove(listener); - if (newListener != null) { - myCaretListeners.removeListener(newListener); - } + myCaretListeners.removeListener(listener); } @Override @@ -270,6 +241,13 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, } @Override + public int getCaretCount() { + synchronized (myCarets) { + return myCarets.size(); + } + } + + @Override @NotNull public List<Caret> getAllCarets() { List<Caret> carets; @@ -403,8 +381,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, } CaretImpl currCaret = it.next(); if (prevCaret != null && (currCaret.getVisualPosition().equals(prevCaret.getVisualPosition()) - || regionsIntersect(currCaret.getSelectionStart(), currCaret.getSelectionEnd(), - prevCaret.getSelectionStart(), prevCaret.getSelectionEnd()))) { + || selectionsIntersect(currCaret, prevCaret))) { int newSelectionStart = Math.min(currCaret.getSelectionStart(), prevCaret.getSelectionStart()); int newSelectionEnd = Math.max(currCaret.getSelectionEnd(), prevCaret.getSelectionEnd()); CaretImpl toRetain, toRemove; @@ -429,10 +406,12 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, } } - private static boolean regionsIntersect(int firstStart, int firstEnd, int secondStart, int secondEnd) { - return firstStart < secondStart && firstEnd > secondStart - || firstStart > secondStart && firstStart < secondEnd - || firstStart == secondStart && secondEnd > secondStart && firstEnd > firstStart; + private static boolean selectionsIntersect(CaretImpl firstCaret, CaretImpl secondCaret) { + return firstCaret.getSelectionStart() < secondCaret.getSelectionStart() && firstCaret.getSelectionEnd() > secondCaret.getSelectionStart() + || firstCaret.getSelectionStart() > secondCaret.getSelectionStart() && firstCaret.getSelectionStart() < secondCaret.getSelectionEnd() + || firstCaret.getSelectionStart() == secondCaret.getSelectionStart() && secondCaret.getSelectionEnd() > secondCaret.getSelectionStart() && firstCaret.getSelectionEnd() > firstCaret.getSelectionStart() + || (firstCaret.getSelectionStart() == firstCaret.getSelectionEnd() && firstCaret.hasVirtualSelection() || secondCaret.getSelectionStart() == secondCaret.getSelectionEnd() && secondCaret.hasVirtualSelection()) + && (firstCaret.getSelectionStart() == secondCaret.getSelectionStart() || firstCaret.getSelectionEnd() == secondCaret.getSelectionEnd()); } void doWithCaretMerging(Runnable runnable) { @@ -452,21 +431,17 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, } @Override - public void setCaretsAndSelections(@NotNull final List<LogicalPosition> caretPositions, @NotNull final List<? extends Segment> selections) { + public void setCaretsAndSelections(@NotNull final List<CaretState> caretStates) { myEditor.assertIsDispatchThread(); - if (caretPositions.isEmpty()) { + if (caretStates.isEmpty()) { throw new IllegalArgumentException("At least one caret should exist"); } - if (caretPositions.size() != selections.size()) { - throw new IllegalArgumentException("Position and selection lists are of different size"); - } doWithCaretMerging(new Runnable() { public void run() { int index = 0; int oldCaretCount = myCarets.size(); Iterator<CaretImpl> caretIterator = myCarets.iterator(); - Iterator<? extends Segment> selectionIterator = selections.iterator(); - for (LogicalPosition caretPosition : caretPositions) { + for (CaretState caretState : caretStates) { CaretImpl caret; boolean caretAdded; if (index++ < oldCaretCount) { @@ -475,8 +450,8 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, } else { caret = new CaretImpl(myEditor); - if (caretPosition != null) { - caret.moveToLogicalPosition(caretPosition, false, null, false); + if (caretState != null && caretState.getCaretPosition() != null) { + caret.moveToLogicalPosition(caretState.getCaretPosition(), false, null, false); } synchronized (myCarets) { myCarets.add(caret); @@ -484,15 +459,16 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, fireCaretAdded(caret); caretAdded = true; } - if (caretPosition != null && !caretAdded) { - caret.moveToLogicalPosition(caretPosition); + if (caretState != null && caretState.getCaretPosition() != null && !caretAdded) { + caret.moveToLogicalPosition(caretState.getCaretPosition()); } - Segment selection = selectionIterator.next(); - if (selection != null) { - caret.setSelection(selection.getStartOffset(), selection.getEndOffset()); + if (caretState != null && caretState.getSelectionStart() != null && caretState.getSelectionEnd() != null) { + caret.setSelection(myEditor.logicalToVisualPosition(caretState.getSelectionStart()), myEditor.logicalPositionToOffset(caretState.getSelectionStart()), + myEditor.logicalToVisualPosition(caretState.getSelectionEnd()), myEditor.logicalPositionToOffset( + caretState.getSelectionEnd())); } } - int caretsToRemove = myCarets.size() - caretPositions.size(); + int caretsToRemove = myCarets.size() - caretStates.size(); for (int i = 0; i < caretsToRemove; i++) { CaretImpl caret; synchronized (myCarets) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorFactoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorFactoryImpl.java index e658e24cb436..611a7c21260d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorFactoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorFactoryImpl.java @@ -132,7 +132,14 @@ public class EditorFactoryImpl extends EditorFactory { @NotNull public Document createDocument(boolean allowUpdatesWithoutWriteAction) { - DocumentImpl document = new DocumentImpl("",allowUpdatesWithoutWriteAction); + DocumentImpl document = new DocumentImpl("", allowUpdatesWithoutWriteAction); + myEditorEventMulticaster.registerDocument(document); + return document; + } + + @NotNull + public Document createDocument(@NotNull CharSequence text, boolean acceptsSlashR, boolean allowUpdatesWithoutWriteAction) { + DocumentImpl document = new DocumentImpl(text, acceptsSlashR, allowUpdatesWithoutWriteAction); myEditorEventMulticaster.registerDocument(document); return document; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 33cebb543c6f..c003d7ba62fa 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -58,6 +58,7 @@ import com.intellij.ui.awt.RelativePoint; import com.intellij.util.Function; import com.intellij.util.IconUtil; import com.intellij.util.NullableFunction; +import com.intellij.util.SmartList; import com.intellij.util.containers.Convertor; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.UIUtil; @@ -401,7 +402,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return myBackgroundColor; } - private boolean isDistractionFreeMode() { + private static boolean isDistractionFreeMode() { return Registry.is("editor.distraction.free.mode"); } @@ -469,9 +470,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse int patchedStartOffset = startOffset < docLength ? document.getLineStartOffset(document.getLineNumber(startOffset)) : docLength; int patchedEndOffset = endOffset <= docLength ? document.getLineEndOffset(document.getLineNumber(endOffset)) + 1 : docLength; DisposableIterator<RangeHighlighterEx> docHighlighters = docMarkup.overlappingIterator(patchedStartOffset, patchedEndOffset); - - final MarkupModelEx editorMarkup = (MarkupModelEx)myEditor.getMarkupModel(); - DisposableIterator<RangeHighlighterEx> editorHighlighters = editorMarkup.overlappingIterator(startOffset, endOffset); + DisposableIterator<RangeHighlighterEx> editorHighlighters = myEditor.getMarkupModel().overlappingIterator(startOffset, endOffset); try { RangeHighlighterEx lastDocHighlighter = null; @@ -504,7 +503,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse if (lastDocHighlighter == null && lastEditorHighlighter == null) return; final RangeHighlighterEx lowerHighlighter; - if (less(lastDocHighlighter, lastEditorHighlighter)) { lowerHighlighter = lastDocHighlighter; lastDocHighlighter = null; @@ -600,23 +598,23 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private TIntObjectHashMap<ArrayList<GutterMark>> myLineToGutterRenderers; + private TIntObjectHashMap<List<GutterMark>> myLineToGutterRenderers; private void calcIconAreaWidth() { - myLineToGutterRenderers = new TIntObjectHashMap<ArrayList<GutterMark>>(); + myLineToGutterRenderers = new TIntObjectHashMap<List<GutterMark>>(); processRangeHighlighters(0, myEditor.getDocument().getTextLength(), new RangeHighlighterProcessor() { @Override public void process(RangeHighlighter highlighter) { GutterMark renderer = highlighter.getGutterIconRenderer(); - if (renderer == null) return; - - int startOffset = highlighter.getStartOffset(); - int line = myEditor.getDocument().getLineNumber(startOffset); + if (renderer == null) { + return; + } - ArrayList<GutterMark> renderers = myLineToGutterRenderers.get(line); + int line = myEditor.getDocument().getLineNumber(highlighter.getStartOffset()); + List<GutterMark> renderers = myLineToGutterRenderers.get(line); if (renderers == null) { - renderers = new ArrayList<GutterMark>(); + renderers = new SmartList<GutterMark>(); myLineToGutterRenderers.put(line, renderers); } @@ -628,9 +626,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse myIconsAreaWidth = START_ICON_AREA_WIDTH; - myLineToGutterRenderers.forEachValue(new TObjectProcedure<ArrayList<GutterMark>>() { + myLineToGutterRenderers.forEachValue(new TObjectProcedure<List<GutterMark>>() { @Override - public boolean execute(ArrayList<GutterMark> renderers) { + public boolean execute(List<GutterMark> renderers) { int width = 1; for (int i = 0; i < renderers.size(); i++) { GutterMark renderer = renderers.get(i); @@ -677,7 +675,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse public boolean execute(int line) { if (firstVisibleLine > line || lastVisibleLine < line) return true; if (isLineCollapsed(line)) return true; - ArrayList<GutterMark> renderers = myLineToGutterRenderers.get(line); + List<GutterMark> renderers = myLineToGutterRenderers.get(line); paintIconRow(line, renderers, g); return true; } @@ -690,7 +688,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return region != null && region.getEndOffset() >= myEditor.getDocument().getLineEndOffset(line); } - private void paintIconRow(int line, ArrayList<GutterMark> row, final Graphics g) { + private void paintIconRow(int line, List<GutterMark> row, final Graphics g) { processIconsRow(line, row, new LineGutterIconRendererProcessor() { @Override public void process(int x, int y, GutterMark renderer) { @@ -743,7 +741,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse void process(int x, int y, GutterMark renderer); } - private void processIconsRow(int line, ArrayList<GutterMark> row, LineGutterIconRendererProcessor processor) { + private void processIconsRow(int line, List<GutterMark> row, LineGutterIconRendererProcessor processor) { int middleCount = 0; int middleSize = 0; int x = getLineMarkerAreaOffset() + 1; @@ -1119,7 +1117,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse if (toolTip != null && !toolTip.isEmpty()) { final Ref<Point> t = new Ref<Point>(e.getPoint()); int line = EditorUtil.yPositionToLogicalLine(myEditor, e); - ArrayList<GutterMark> row = myLineToGutterRenderers.get(line); + List<GutterMark> row = myLineToGutterRenderers.get(line); Balloon.Position ballPosition = Balloon.Position.atRight; if (row != null) { final TreeMap<Integer, GutterMark> xPos = new TreeMap<Integer, GutterMark>(); @@ -1421,8 +1419,10 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private GutterMark getGutterRenderer(final Point p) { int line = convertPointToLineNumber(p); if (line == -1) return null; - ArrayList<GutterMark> renderers = myLineToGutterRenderers.get(line); - if (renderers == null) return null; + List<GutterMark> renderers = myLineToGutterRenderers.get(line); + if (renderers == null) { + return null; + } final GutterMark[] result = {null}; processIconsRow(line, renderers, new LineGutterIconRendererProcessor() { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index aa04b488cf29..8b4192947be8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -393,7 +393,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myFoldingModel.addListener(mySoftWrapModel, myCaretModel); myIndentsModel = new IndentsModelImpl(this); - myCaretModel.addCaretListener(new MultipleCaretListener() { + myCaretModel.addCaretListener(new CaretListener() { @Nullable private LightweightHint myCurrentHint = null; @Nullable private IndentGuideDescriptor myCurrentCaretGuide = null; @@ -2289,6 +2289,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi position.x = drawSoftWrapAwareBackground(g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType, defaultBackground, clip, softWrapsToSkip, caretRowPainted); + paintAfterLineEndBackgroundSegments(g, iterationState, position, defaultBackground, lineHeight); + if (lIterator.getLineNumber() < lastLineIndex) { if (backColor != null && !backColor.equals(defaultBackground)) { g.setColor(backColor); @@ -2296,6 +2298,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } else { + if (iterationState.hasPastFileEndBackgroundSegments()) { + paintAfterLineEndBackgroundSegments(g, iterationState, position, defaultBackground, lineHeight); + } paintAfterFileEndBackground(iterationState, g, position, clip, @@ -2380,6 +2385,24 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } + private void paintAfterLineEndBackgroundSegments(@NotNull Graphics g, + @NotNull IterationState iterationState, + @NotNull Point position, + @NotNull Color defaultBackground, + int lineHeight) { + while (iterationState.hasPastLineEndBackgroundSegment()) { + TextAttributes backgroundAttributes = iterationState.getPastLineEndBackgroundAttributes(); + int width = EditorUtil.getSpaceWidth(backgroundAttributes.getFontType(), this) * iterationState.getPastLineEndBackgroundSegmentWidth(); + Color color = getBackgroundColor(backgroundAttributes); + if (color != null && !color.equals(defaultBackground)) { + g.setColor(color); + g.fillRect(position.x, position.y, width, lineHeight); + } + position.x += width; + iterationState.advanceToNextPastLineEndBackgroundSegment(); + } + } + private void paintRectangularSelection(@NotNull Graphics g) { final SelectionModel model = getSelectionModel(); if (!model.hasBlockSelection()) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java index 962230e8680e..8349aac12497 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java @@ -45,7 +45,6 @@ import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.awt.*; import java.util.Arrays; import java.util.List; @@ -201,7 +200,6 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList } private void runBatchFoldingOperation(final Runnable operation, final boolean dontCollapseCaret, final boolean moveCaret) { - assert SwingUtilities.isEventDispatchThread() : Thread.currentThread(); assertIsDispatchThreadForEditor(); boolean oldDontCollapseCaret = myDoNotCollapseCaret; myDoNotCollapseCaret |= dontCollapseCaret; @@ -212,17 +210,20 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList myIsBatchFoldingProcessing = true; myFoldTree.myCachedLastIndex = -1; - operation.run(); - myFoldTree.myCachedLastIndex = -1; - - if (!oldBatchFlag) { - if (myFoldRegionsProcessed) { - notifyBatchFoldingProcessingDone(moveCaret); - myFoldRegionsProcessed = false; + try { + operation.run(); + } finally { + myFoldTree.myCachedLastIndex = -1; + + if (!oldBatchFlag) { + if (myFoldRegionsProcessed) { + notifyBatchFoldingProcessingDone(moveCaret); + myFoldRegionsProcessed = false; + } + myIsBatchFoldingProcessing = false; } - myIsBatchFoldingProcessing = false; + myDoNotCollapseCaret = oldDontCollapseCaret; } - myDoNotCollapseCaret = oldDontCollapseCaret; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java index 3f3ed7e054a1..4bd96fdda625 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java @@ -17,13 +17,17 @@ package com.intellij.openapi.editor.impl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.FoldRegion; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.ex.*; import com.intellij.openapi.editor.highlighter.HighlighterIterator; -import com.intellij.openapi.editor.markup.*; +import com.intellij.openapi.editor.markup.EffectType; +import com.intellij.openapi.editor.markup.HighlighterLayer; +import com.intellij.openapi.editor.markup.HighlighterTargetArea; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.Comparing; import com.intellij.util.ArrayUtilRt; import com.intellij.util.containers.ContainerUtil; @@ -89,7 +93,13 @@ public final class IterationState { private final int[] mySelectionStarts; private final int[] mySelectionEnds; + private final int[] myVirtualSelectionStarts; + private final int[] myVirtualSelectionEnds; private int myCurrentSelectionIndex = 0; + private int myCurrentVirtualSelectionIndex = 0; + private boolean myCurrentLineHasVirtualSelection; + private int myCurrentPastLineEndBackgroundSegment; // 0 - before selection, 1 - in selection, 2 - after selection + private Color myCurrentBackgroundColor; private final List<RangeHighlighterEx> myCurrentHighlighters = new ArrayList<RangeHighlighterEx>(); @@ -123,8 +133,32 @@ public final class IterationState { myHighlighterIterator = editor.getHighlighter().createIterator(start); boolean hasSelection = useCaretAndSelection && (editor.getCaretModel().supportsMultipleCarets() || editor.getSelectionModel().hasSelection() || editor.getSelectionModel().hasBlockSelection()); - mySelectionStarts = hasSelection ? editor.getSelectionModel().getBlockSelectionStarts() : ArrayUtilRt.EMPTY_INT_ARRAY; - mySelectionEnds = hasSelection ? editor.getSelectionModel().getBlockSelectionEnds() : ArrayUtilRt.EMPTY_INT_ARRAY; + if (!hasSelection) { + mySelectionStarts = ArrayUtilRt.EMPTY_INT_ARRAY; + mySelectionEnds = ArrayUtilRt.EMPTY_INT_ARRAY; + myVirtualSelectionStarts = ArrayUtilRt.EMPTY_INT_ARRAY; + myVirtualSelectionEnds = ArrayUtilRt.EMPTY_INT_ARRAY; + } + else if (editor.getCaretModel().supportsMultipleCarets()) { + List<Caret> carets = editor.getCaretModel().getAllCarets(); + mySelectionStarts = new int[carets.size()]; + mySelectionEnds = new int[carets.size()]; + myVirtualSelectionStarts = new int[carets.size()]; + myVirtualSelectionEnds = new int[carets.size()]; + for (int i = 0; i < carets.size(); i++) { + Caret caret = carets.get(i); + mySelectionStarts[i] = caret.getSelectionStart(); + mySelectionEnds[i] = caret.getSelectionEnd(); + myVirtualSelectionStarts[i] = caret.getSelectionStartPosition().column - editor.offsetToVisualPosition(mySelectionStarts[i]).column; + myVirtualSelectionEnds[i] = caret.getSelectionEndPosition().column - editor.offsetToVisualPosition(mySelectionEnds[i]).column; + } + } + else { + mySelectionStarts = editor.getSelectionModel().getBlockSelectionStarts(); + mySelectionEnds = editor.getSelectionModel().getBlockSelectionEnds(); + myVirtualSelectionStarts = new int[mySelectionStarts.length]; + myVirtualSelectionEnds = new int[mySelectionEnds.length]; + } myFoldingModel = editor.getFoldingModel(); myFoldTextAttributes = myFoldingModel.getPlaceholderAttributes(); @@ -140,7 +174,7 @@ public final class IterationState { myCaretRowStart = caretModel.getVisualLineStart(); myCaretRowEnd = caretModel.getVisualLineEnd(); - MarkupModelEx editorMarkup = (MarkupModelEx)editor.getMarkupModel(); + MarkupModelEx editorMarkup = editor.getMarkupModel(); myView = new HighlighterSweep(editorMarkup, start, myEnd); final MarkupModelEx docMarkup = (MarkupModelEx)DocumentMarkupModel.forDocument(editor.getDocument(), editor.getProject(), true); @@ -181,31 +215,20 @@ public final class IterationState { private void advance() { if (myNextHighlighter != null) { - if (myNextHighlighter.getAffectedAreaStartOffset() <= myStartOffset) { - myCurrentHighlighters.add(myNextHighlighter); - myNextHighlighter = null; - } - - // There is a possible case that there are two highlighters mapped to offset of the first non-white space symbol - // on a line. The second one may have HighlighterTargetArea.LINES_IN_RANGE area, so, we should use it for indent - // background processing (that is the case for the active debugger line that starts with highlighted brace/bracket). - // So, we check if it's worth to use next highlighter here. - else if (myIterator.hasNext()) { - final RangeHighlighterEx lookAhead = myIterator.next(); - if (lookAhead.getAffectedAreaStartOffset() <= myStartOffset) { - myCurrentHighlighters.add(lookAhead); - } - else { - myIterator.pushBack(lookAhead); - } + if (myNextHighlighter.getAffectedAreaStartOffset() > myStartOffset) { + return; } + + myCurrentHighlighters.add(myNextHighlighter); + myNextHighlighter = null; } - while (myNextHighlighter == null && myIterator.hasNext()) { + while (myIterator.hasNext()) { RangeHighlighterEx highlighter = myIterator.next(); if (!skipHighlighter(highlighter)) { if (highlighter.getAffectedAreaStartOffset() > myStartOffset) { myNextHighlighter = highlighter; + break; } else { myCurrentHighlighters.add(highlighter); @@ -237,6 +260,7 @@ public final class IterationState { myStartOffset = myEndOffset; advanceSegmentHighlighters(); advanceCurrentSelectionIndex(); + advanceCurrentVirtualSelectionIndex(); myCurrentFold = myFoldingModel.fetchOutermost(myStartOffset); if (myCurrentFold != null) { @@ -298,6 +322,13 @@ public final class IterationState { } } + private void advanceCurrentVirtualSelectionIndex() { + while (myCurrentVirtualSelectionIndex < mySelectionEnds.length + && (myStartOffset > mySelectionEnds[myCurrentVirtualSelectionIndex] || myVirtualSelectionEnds[myCurrentVirtualSelectionIndex] <= 0)) { + myCurrentVirtualSelectionIndex++; + } + } + private int getSelectionEnd() { if (myCurrentSelectionIndex >= mySelectionStarts.length) { return myEnd; @@ -402,12 +433,17 @@ public final class IterationState { List<TextAttributes> cachedAttributes = myCachedAttributesList; cachedAttributes.clear(); + int selectionAttributesIndex = -1; // a 'would-be' or real position of selection attributes in attributes list + //noinspection ForLoopReplaceableByForEach for (int i = 0; i < size; i++) { RangeHighlighterEx highlighter = myCurrentHighlighters.get(i); - if (selection != null && highlighter.getLayer() < HighlighterLayer.SELECTION) { - cachedAttributes.add(selection); - selection = null; + if (highlighter.getLayer() < HighlighterLayer.SELECTION) { + selectionAttributesIndex = cachedAttributes.size(); + if (selection != null) { + cachedAttributes.add(selection); + selection = null; + } } if (syntax != null && highlighter.getLayer() < HighlighterLayer.SYNTAX) { @@ -436,6 +472,9 @@ public final class IterationState { } } + if (selectionAttributesIndex < 0) { + selectionAttributesIndex = cachedAttributes.size(); + } if (selection != null) cachedAttributes.add(selection); if (fold != null) cachedAttributes.add(fold); if (guard != null) cachedAttributes.add(guard); @@ -448,6 +487,8 @@ public final class IterationState { EffectType effectType = null; int fontType = 0; + boolean selectionBackgroundIsPotentiallyVisible = cachedAttributes.isEmpty(); + //noinspection ForLoopReplaceableByForEach for (int i = 0; i < cachedAttributes.size(); i++) { TextAttributes attrs = cachedAttributes.get(i); @@ -457,6 +498,9 @@ public final class IterationState { } if (back == null) { + if (isInSelection && i == selectionAttributesIndex || !isInSelection && i >= selectionAttributesIndex) { + selectionBackgroundIsPotentiallyVisible = true; + } back = ifDiffers(attrs.getBackgroundColor(), myDefaultBackground); } @@ -475,6 +519,16 @@ public final class IterationState { if (effectType == null) effectType = EffectType.BOXED; myMergedAttributes.setAttributes(fore, back, effect, null, effectType, fontType); + + myCurrentBackgroundColor = back; + if (selectionBackgroundIsPotentiallyVisible && myCurrentVirtualSelectionIndex < mySelectionStarts.length && myStartOffset == mySelectionEnds[myCurrentVirtualSelectionIndex]) { + myCurrentLineHasVirtualSelection = true; + myCurrentPastLineEndBackgroundSegment = myVirtualSelectionStarts[myCurrentVirtualSelectionIndex] > 0 ? 0 : 1; + } + else { + myCurrentLineHasVirtualSelection = false; + myCurrentPastLineEndBackgroundSegment = 0; + } } @Nullable @@ -504,6 +558,41 @@ public final class IterationState { return myCurrentFold; } + public boolean hasPastLineEndBackgroundSegment() { + return myCurrentLineHasVirtualSelection && myCurrentPastLineEndBackgroundSegment < 2; + } + + public int getPastLineEndBackgroundSegmentWidth() { + switch (myCurrentPastLineEndBackgroundSegment) { + case 0: return myVirtualSelectionStarts[myCurrentVirtualSelectionIndex]; + case 1: return myVirtualSelectionEnds[myCurrentVirtualSelectionIndex] - myVirtualSelectionStarts[myCurrentVirtualSelectionIndex]; + default: return 0; + } + } + + @NotNull + public TextAttributes getPastLineEndBackgroundAttributes() { + myMergedAttributes.setBackgroundColor(myCurrentPastLineEndBackgroundSegment == 1 ? mySelectionAttributes.getBackgroundColor() : myCurrentBackgroundColor); + return myMergedAttributes; + } + + public void advanceToNextPastLineEndBackgroundSegment() { + myCurrentPastLineEndBackgroundSegment++; + } + + public boolean hasPastFileEndBackgroundSegments() { + myCurrentLineHasVirtualSelection = myVirtualSelectionEnds.length > 0 + && myVirtualSelectionEnds[myVirtualSelectionEnds.length - 1] > 0 + && myEndOffset == myEnd + && mySelectionEnds[mySelectionStarts.length - 1] == myEndOffset; + if (myCurrentLineHasVirtualSelection) { + myCurrentVirtualSelectionIndex = myVirtualSelectionStarts.length - 1; + myCurrentPastLineEndBackgroundSegment = myVirtualSelectionStarts[myCurrentVirtualSelectionIndex] > 0 ? 0 : 1; + myCurrentBackgroundColor = myEndOffset >= myCaretRowStart ? myCaretRowAttributes.getBackgroundColor() : myDefaultBackground; + } + return myCurrentLineHasVirtualSelection; + } + @Nullable public Color getPastFileEndBackground() { boolean isInCaretRow = myEditor.getCaretModel().getLogicalPosition().line >= myDocument.getLineCount() - 1; @@ -543,8 +632,8 @@ public final class IterationState { return layerDiff; } // prefer more specific region - int o1Length = o1.getEndOffset() - o1.getStartOffset(); - int o2Length = o2.getEndOffset() - o2.getStartOffset(); + int o1Length = o1.getAffectedAreaEndOffset() - o1.getAffectedAreaStartOffset(); + int o2Length = o2.getAffectedAreaEndOffset() - o2.getAffectedAreaStartOffset(); return o1Length - o2Length; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java index 46be8b85a5cf..7ee0e4d2668d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java @@ -38,7 +38,6 @@ import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; @@ -47,7 +46,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.datatransfer.StringSelection; -import java.util.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentListener { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.SelectionModelImpl"); @@ -214,42 +216,40 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi int endLine = Math.max(Math.min(blockEnd.line, myEditor.getDocument().getLineCount() - 1), 0); int step = endLine < startLine ? -1 : 1; int count = 1 + Math.abs(endLine - startLine); - List<LogicalPosition> positions = new LinkedList<LogicalPosition>(); - List<TextRange> selections = new LinkedList<TextRange>(); + List<CaretState> caretStates = new LinkedList<CaretState>(); boolean hasSelection = false; for (int line = startLine, i = 0; i < count; i++, line += step) { int startColumn = blockStart.column; int endColumn = blockEnd.column; int lineEndOffset = myEditor.getDocument().getLineEndOffset(line); - int lineWidth = myEditor.offsetToLogicalPosition(lineEndOffset).column; - if (startColumn > lineWidth && endColumn > lineWidth) { + LogicalPosition lineEndPosition = myEditor.offsetToLogicalPosition(lineEndOffset); + int lineWidth = lineEndPosition.column; + if (startColumn > lineWidth && endColumn > lineWidth && !myEditor.isColumnMode()) { LogicalPosition caretPos = new LogicalPosition(line, Math.min(startColumn, endColumn)); - positions.add(caretPos); - selections.add(new TextRange(lineEndOffset, lineEndOffset)); + caretStates.add(new CaretState(caretPos, + lineEndPosition, + lineEndPosition)); } else { - LogicalPosition startPos = new LogicalPosition(line, Math.min(startColumn, lineWidth)); - LogicalPosition endPos = new LogicalPosition(line, Math.min(endColumn, lineWidth)); + LogicalPosition startPos = new LogicalPosition(line, myEditor.isColumnMode() ? startColumn : Math.min(startColumn, lineWidth)); + LogicalPosition endPos = new LogicalPosition(line, myEditor.isColumnMode() ? endColumn : Math.min(endColumn, lineWidth)); int startOffset = myEditor.logicalPositionToOffset(startPos); int endOffset = myEditor.logicalPositionToOffset(endPos); - positions.add(endPos); - selections.add(new TextRange(Math.min(startOffset, endOffset), Math.max(startOffset, endOffset))); + caretStates.add(new CaretState(endPos, startPos, endPos)); hasSelection |= startOffset != endOffset; } } if (hasSelection && !myEditor.isColumnMode()) { // filtering out lines without selection - Iterator<LogicalPosition> positionIterator = positions.iterator(); - Iterator<TextRange> selectionIterator = selections.iterator(); - while(selectionIterator.hasNext()) { - TextRange selection = selectionIterator.next(); - positionIterator.next(); - if (selection.isEmpty()) { - selectionIterator.remove(); - positionIterator.remove(); + Iterator<CaretState> caretStateIterator = caretStates.iterator(); + while(caretStateIterator.hasNext()) { + CaretState state = caretStateIterator.next(); + //noinspection ConstantConditions + if (state.getSelectionStart().equals(state.getSelectionEnd())) { + caretStateIterator.remove(); } } } - myEditor.getCaretModel().setCaretsAndSelections(positions, selections); + myEditor.getCaretModel().setCaretsAndSelections(caretStates); } else { removeSelection(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaretModel.java b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaretModel.java index 607e182dd3cb..ef86c6f3ae3d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaretModel.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaretModel.java @@ -18,7 +18,6 @@ package com.intellij.openapi.editor.textarea; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.util.Segment; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -151,6 +150,11 @@ public class TextComponentCaretModel implements CaretModel { return myCaret; } + @Override + public int getCaretCount() { + return 1; + } + @NotNull @Override public List<Caret> getAllCarets() { @@ -179,7 +183,7 @@ public class TextComponentCaretModel implements CaretModel { } @Override - public void setCaretsAndSelections(@NotNull List<LogicalPosition> caretPositions, @NotNull List<? extends Segment> selections) { + public void setCaretsAndSelections(@NotNull List<CaretState> caretStates) { throw new UnsupportedOperationException("Multiple carets are not supported"); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java index 978c26068655..32169662ba2a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java @@ -41,6 +41,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; @@ -141,7 +142,7 @@ public final class EditorHistoryManager extends AbstractProjectComponent impleme } LOG.assertTrue(selectedEditor != null); final int selectedProviderIndex = ArrayUtilRt.find(editors, selectedEditor); - LOG.assertTrue(selectedProviderIndex != -1); + LOG.assertTrue(selectedProviderIndex != -1, "Can't find " + selectedEditor + " among " + Arrays.asList(editors)); final HistoryEntry entry = getEntry(file); if(entry != null){ diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java index 14af91d690f1..54803815c898 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java @@ -37,6 +37,7 @@ import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; +import com.intellij.openapi.editor.impl.EditorFactoryImpl; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl; @@ -184,7 +185,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl document = (DocumentEx)getCachedDocument(file); if (document != null) return document; // Double checking - document = (DocumentEx)createDocument(text); + document = (DocumentEx)createDocument(text, file); document.setModificationStamp(file.getModificationStamp()); final FileType fileType = file.getFileType(); document.setReadOnly(!file.isWritable() || fileType.isBinary()); @@ -229,8 +230,9 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl return false; } - private static Document createDocument(final CharSequence text) { - return EditorFactory.getInstance().createDocument(text); + private static Document createDocument(final CharSequence text, VirtualFile file) { + boolean acceptSlashR = file instanceof LightVirtualFile && StringUtil.indexOf(text, '\r') >= 0; + return ((EditorFactoryImpl)EditorFactory.getInstance()).createDocument(text, acceptSlashR, false); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java index 6e80c6da70fa..752ab1228c3e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java @@ -119,7 +119,7 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec }; eventMulticaster.addDocumentListener(documentListener, myProject); - CaretListener caretListener = new CaretListener() { + CaretListener caretListener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { onCaretPositionChanged(e); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java index 1ffd02740387..d7b881a0cba4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java @@ -50,6 +50,7 @@ import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.StatusBarEx; import com.intellij.ui.components.JBLoadingPanel; import com.intellij.util.EditorPopupHandler; +import com.intellij.util.FileContentUtilCore; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -348,7 +349,9 @@ class TextEditorComponent extends JBLoadingPanel implements DataProvider { // File can be invalidated after file changes name (extension also // can changes). The editor should be removed if it's invalid. updateValidProperty(); - if (Comparing.equal(e.getFile(), myFile) && !Comparing.equal(e.getOldValue(), e.getNewValue())) { + if (Comparing.equal(e.getFile(), myFile) && + (FileContentUtilCore.FORCE_RELOAD_REQUESTOR.equals(e.getRequestor()) || + !Comparing.equal(e.getOldValue(), e.getNewValue()))) { updateHighlighters(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java index 4514ee8fbe58..47c0088fa2ce 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java @@ -57,8 +57,10 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { @NonNls private static final String TYPE_ID = "text-editor"; @NonNls private static final String LINE_ATTR = "line"; @NonNls private static final String COLUMN_ATTR = "column"; - @NonNls private static final String SELECTION_START_ATTR = "selection-start"; - @NonNls private static final String SELECTION_END_ATTR = "selection-end"; + @NonNls private static final String SELECTION_START_LINE_ATTR = "selection-start-line"; + @NonNls private static final String SELECTION_START_COLUMN_ATTR = "selection-start-column"; + @NonNls private static final String SELECTION_END_LINE_ATTR = "selection-end-line"; + @NonNls private static final String SELECTION_END_COLUMN_ATTR = "selection-end-column"; @NonNls private static final String VERTICAL_SCROLL_PROPORTION_ATTR = "vertical-scroll-proportion"; @NonNls private static final String VERTICAL_OFFSET_ATTR = "vertical-offset"; @NonNls private static final String MAX_VERTICAL_OFFSET_ATTR = "max-vertical-offset"; @@ -100,10 +102,10 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { try { List<Element> caretElements = element.getChildren(CARET_ELEMENT); - if (caretElements.isEmpty()) { // legacy format + if (caretElements.isEmpty()) { state.CARETS = new TextEditorState.CaretState[] {readCaretInfo(element)}; } - else { // new format + else { state.CARETS = new TextEditorState.CaretState[caretElements.size()]; for (int i = 0; i < caretElements.size(); i++) { state.CARETS[i] = readCaretInfo(caretElements.get(i)); @@ -129,8 +131,10 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { TextEditorState.CaretState caretState = new TextEditorState.CaretState(); caretState.LINE = parseWithDefault(element, LINE_ATTR); caretState.COLUMN = parseWithDefault(element, COLUMN_ATTR); - caretState.SELECTION_START = parseWithDefault(element, SELECTION_START_ATTR); - caretState.SELECTION_END = parseWithDefault(element, SELECTION_END_ATTR); + caretState.SELECTION_START_LINE = parseWithDefault(element, SELECTION_START_LINE_ATTR); + caretState.SELECTION_START_COLUMN = parseWithDefault(element, SELECTION_START_COLUMN_ATTR); + caretState.SELECTION_END_LINE = parseWithDefault(element, SELECTION_END_LINE_ATTR); + caretState.SELECTION_END_COLUMN = parseWithDefault(element, SELECTION_END_COLUMN_ATTR); return caretState; } @@ -151,8 +155,10 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { Element e = new Element(CARET_ELEMENT); e.setAttribute(LINE_ATTR, Integer.toString(caretState.LINE)); e.setAttribute(COLUMN_ATTR, Integer.toString(caretState.COLUMN)); - e.setAttribute(SELECTION_START_ATTR, Integer.toString(caretState.SELECTION_START)); - e.setAttribute(SELECTION_END_ATTR, Integer.toString(caretState.SELECTION_END)); + e.setAttribute(SELECTION_START_LINE_ATTR, Integer.toString(caretState.SELECTION_START_LINE)); + e.setAttribute(SELECTION_START_COLUMN_ATTR, Integer.toString(caretState.SELECTION_START_COLUMN)); + e.setAttribute(SELECTION_END_LINE_ATTR, Integer.toString(caretState.SELECTION_END_LINE)); + e.setAttribute(SELECTION_END_COLUMN_ATTR, Integer.toString(caretState.SELECTION_END_COLUMN)); element.addContent(e); } } @@ -227,8 +233,12 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { state.CARETS[i] = new TextEditorState.CaretState(); state.CARETS[i].LINE = caret.getLogicalPosition().line; state.CARETS[i].COLUMN = caret.getLogicalPosition().column; - state.CARETS[i].SELECTION_START = caret.getSelectionStart(); - state.CARETS[i++].SELECTION_END = caret.getSelectionEnd(); + LogicalPosition selectionStartPosition = editor.visualToLogicalPosition(caret.getSelectionStartPosition()); + LogicalPosition selectionEndPosition = editor.visualToLogicalPosition(caret.getSelectionEndPosition()); + state.CARETS[i].SELECTION_START_LINE = selectionStartPosition.line; + state.CARETS[i].SELECTION_START_COLUMN = selectionStartPosition.column; + state.CARETS[i].SELECTION_END_LINE = selectionEndPosition.line; + state.CARETS[i++].SELECTION_END_COLUMN = selectionEndPosition.column; } // Saving scrolling proportion on UNDO may cause undesirable results of undo action fails to perform since @@ -246,13 +256,13 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { protected void setStateImpl(final Project project, final Editor editor, final TextEditorState state){ if (editor.getCaretModel().supportsMultipleCarets()) { CaretModel caretModel = editor.getCaretModel(); - ArrayList<LogicalPosition> positions = new ArrayList<LogicalPosition>(); - ArrayList<Segment> selections = new ArrayList<Segment>(); + List<CaretState> states = new ArrayList<CaretState>(state.CARETS.length); for (TextEditorState.CaretState caretState : state.CARETS) { - positions.add(new LogicalPosition(caretState.LINE, caretState.COLUMN)); - selections.add(new TextRange(caretState.SELECTION_START, caretState.SELECTION_END)); + states.add(new CaretState(new LogicalPosition(caretState.LINE, caretState.COLUMN), + new LogicalPosition(caretState.SELECTION_START_LINE, caretState.SELECTION_START_COLUMN), + new LogicalPosition(caretState.SELECTION_END_LINE, caretState.SELECTION_END_COLUMN))); } - caretModel.setCaretsAndSelections(positions, selections); + caretModel.setCaretsAndSelections(states); } else { LogicalPosition pos = new LogicalPosition(state.CARETS[0].LINE, state.CARETS[0].COLUMN); editor.getCaretModel().moveToLogicalPosition(pos); @@ -275,15 +285,14 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { } } - final Document document = editor.getDocument(); - if (!editor.getCaretModel().supportsMultipleCarets()) { - if (state.CARETS[0].SELECTION_START == state.CARETS[0].SELECTION_END) { + if (state.CARETS[0].SELECTION_START_LINE == state.CARETS[0].SELECTION_END_LINE + && state.CARETS[0].SELECTION_START_COLUMN == state.CARETS[0].SELECTION_END_COLUMN) { editor.getSelectionModel().removeSelection(); } else { - int startOffset = Math.min(state.CARETS[0].SELECTION_START, document.getTextLength()); - int endOffset = Math.min(state.CARETS[0].SELECTION_END, document.getTextLength()); + int startOffset = editor.logicalPositionToOffset(new LogicalPosition(state.CARETS[0].SELECTION_START_LINE, state.CARETS[0].SELECTION_START_COLUMN)); + int endOffset = editor.logicalPositionToOffset(new LogicalPosition(state.CARETS[0].SELECTION_END_LINE, state.CARETS[0].SELECTION_END_COLUMN)); editor.getSelectionModel().setSelection(startOffset, endOffset); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorState.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorState.java index 3319d511e1a1..d4aca486c041 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorState.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorState.java @@ -122,8 +122,10 @@ public final class TextEditorState implements FileEditorState { public static class CaretState { public int LINE; public int COLUMN; - public int SELECTION_START; - public int SELECTION_END; + public int SELECTION_START_LINE; + public int SELECTION_START_COLUMN; + public int SELECTION_END_LINE; + public int SELECTION_END_COLUMN; public boolean equals(Object o) { if (!(o instanceof CaretState)) { @@ -134,8 +136,10 @@ public final class TextEditorState implements FileEditorState { if (COLUMN != caretState.COLUMN) return false; if (LINE != caretState.LINE) return false; - if (SELECTION_START != caretState.SELECTION_START) return false; - if (SELECTION_END != caretState.SELECTION_END) return false; + if (SELECTION_START_LINE != caretState.SELECTION_START_LINE) return false; + if (SELECTION_START_COLUMN != caretState.SELECTION_START_COLUMN) return false; + if (SELECTION_END_LINE != caretState.SELECTION_END_LINE) return false; + if (SELECTION_END_COLUMN != caretState.SELECTION_END_COLUMN) return false; return true; } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java index 77e55ea28d26..817cdaa5e458 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java @@ -651,8 +651,8 @@ public final class IdeKeyEventDispatcher implements Disposable { if (!(component instanceof JComponent)) { continue; } - ArrayList listOfActions = (ArrayList)((JComponent)component).getClientProperty(AnAction.ourClientProperty); - if (listOfActions == null) { + List<AnAction> listOfActions = ActionUtil.getActions((JComponent)component); + if (listOfActions.isEmpty()) { continue; } for (Object listOfAction : listOfActions) { diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java index b8095397e016..94f72f6da840 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java @@ -19,6 +19,7 @@ import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.actionSystem.impl.PresentationFactory; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; @@ -78,21 +79,16 @@ public final class IdeMouseEventDispatcher { // here we try to find "local" shortcuts if (component instanceof JComponent) { - @SuppressWarnings("unchecked") - final ArrayList<AnAction> listOfActions = (ArrayList<AnAction>)((JComponent)component).getClientProperty(AnAction.ourClientProperty); - if (listOfActions != null) { - for (AnAction action : listOfActions) { - final Shortcut[] shortcuts = action.getShortcutSet().getShortcuts(); - for (Shortcut shortcut : shortcuts) { - if (mouseShortcut.equals(shortcut) && !myActions.contains(action)) { - myActions.add(action); - } + for (AnAction action : ActionUtil.getActions((JComponent)component)) { + for (Shortcut shortcut : action.getShortcutSet().getShortcuts()) { + if (mouseShortcut.equals(shortcut) && !myActions.contains(action)) { + myActions.add(action); } } - // once we've found a proper local shortcut(s), we exit - if (! myActions.isEmpty()) { - return; - } + } + // once we've found a proper local shortcut(s), we exit + if (!myActions.isEmpty()) { + return; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/DefaultProject.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/DefaultProject.java index 5751e4a1d28b..ada78025bd3e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/DefaultProject.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/DefaultProject.java @@ -15,8 +15,6 @@ */ package com.intellij.openapi.project.impl; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.ProjectManager; import org.jetbrains.annotations.NotNull; @@ -34,13 +32,4 @@ public class DefaultProject extends ProjectImpl { public boolean isDefault() { return true; } - - @Override - public synchronized void dispose() { - if (!ApplicationManager.getApplication().isDisposeInProgress() && !ApplicationManager.getApplication().isUnitTestMode()) { - Logger.getInstance(DefaultProject.class).error(new Exception("Too young to die")); - } - - super.dispose(); - } } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index 35586cf8c8d6..90cbffe3d96b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -263,7 +263,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt private void initProject(@NotNull ProjectImpl project, @Nullable ProjectImpl template) throws IOException { final ProgressIndicator indicator = myProgressManager.getProgressIndicator(); - if (indicator != null) { + if (indicator != null && !project.isDefault()) { indicator.setText(ProjectBundle.message("loading.components.for", project.getName())); indicator.setIndeterminate(true); } @@ -299,6 +299,10 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt } private static void scheduleDispose(final ProjectImpl project) { + if (project.isDefault()) { + return; + } + ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java index aa7b6b3874e7..d54bfcc304b4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java @@ -251,6 +251,7 @@ public class PluginsAdvertiser implements StartupActivity { if (project.isDisposed()) return; if (extensions == null) { loadSupportedExtensions(myAllPlugins); + if (project.isDisposed()) return; EditorNotifications.getInstance(project).updateAllNotifications(); } final Map<String, Plugin> ids = new HashMap<String, Plugin>(); @@ -280,7 +281,9 @@ public class PluginsAdvertiser implements StartupActivity { for (IdeaPluginDescriptor loadedPlugin : myAllPlugins) { final PluginId pluginId = loadedPlugin.getPluginId(); - if (ids.containsKey(pluginId.getIdString()) && !disabledPlugins.contains(pluginId.getIdString())) { + if (ids.containsKey(pluginId.getIdString()) && + !disabledPlugins.contains(pluginId.getIdString()) && + !PluginManagerCore.isBrokenPlugin(loadedPlugin)) { myPlugins.add(PluginDownloader.createDownloader(loadedPlugin)); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/VirtualFileImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/VirtualFileImpl.java index 3c1922e29ec8..be96d70a9db3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/VirtualFileImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/VirtualFileImpl.java @@ -1,6 +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. @@ -45,6 +44,7 @@ abstract class VirtualFileImpl extends VirtualFile implements VirtualFileWithId return myFileSystem; } + @NotNull @Override public String getPath() { if (myParent == null) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/VirtualFileImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/VirtualFileImpl.java index 110d71003867..873ac0200b16 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/VirtualFileImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/VirtualFileImpl.java @@ -102,6 +102,7 @@ class VirtualFileImpl extends HttpVirtualFile { return myFileSystem; } + @NotNull @Override public String getPath() { return myPath; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java index 7f0b5e8a4e9d..e12d756d901e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.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. @@ -260,14 +260,14 @@ public class JarHandler extends JarHandlerBase { private final byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, CacheLibraryInfo value) throws IOException { + public void save(@NotNull DataOutput out, CacheLibraryInfo value) throws IOException { IOUtil.writeUTFFast(myBuffer, out, value.mySnapshotPath); out.writeLong(value.myModificationTime); out.writeLong(value.myFileLength); } @Override - public CacheLibraryInfo read(DataInput in) throws IOException { + public CacheLibraryInfo read(@NotNull DataInput in) throws IOException { return new CacheLibraryInfo(IOUtil.readUTFFast(myBuffer, in), in.readLong(), in.readLong()); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FakeVirtualFile.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FakeVirtualFile.java index 24861243f093..5dc589fa7b66 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FakeVirtualFile.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FakeVirtualFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ public class FakeVirtualFile extends StubVirtualFile { return myParent; } + @NotNull @Override public String getPath() { final String basePath = myParent.getPath(); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java index ab9655a75c03..3f2c4abebf7f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.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. @@ -42,12 +42,12 @@ public class FileNameCache { public static int storeName(@NotNull String name) { final int idx = FSRecords.getNameId(name); - cacheData(name, idx); + cacheData(name, idx, calcStripeIdFromNameId(idx)); return idx; } @NotNull - private static IntObjectLinkedMap.MapEntry<Object> cacheData(String name, int id) { + private static IntObjectLinkedMap.MapEntry<Object> cacheData(String name, int id, int stripe) { if (name == null) { ourNames.markCorrupted(); throw new RuntimeException("VFS name enumerator corrupted"); @@ -55,7 +55,6 @@ public class FileNameCache { Object rawName = convertToBytesIfAsciiString(name); IntObjectLinkedMap.MapEntry<Object> entry = new IntObjectLinkedMap.MapEntry<Object>(id, rawName); - final int stripe = calcStripeIdFromNameId(id); synchronized (ourNameCache[stripe]) { return ourNameCache[stripe].cacheEntry(entry); } @@ -99,7 +98,7 @@ public class FileNameCache { } } - return cacheData(FSRecords.getNameByNameId(id), id); + return cacheData(FSRecords.getNameByNameId(id), id, stripe); } @NotNull diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileImpl.java index 33c024fc5cfe..94f73699ef99 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; +import com.intellij.util.LineSeparator; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -124,4 +125,19 @@ public class VirtualFileImpl extends VirtualFileSystemEntry { public OutputStream getOutputStream(final Object requestor, final long modStamp, final long timeStamp) throws IOException { return VfsUtilCore.outputStreamAddingBOM(ourPersistence.getOutputStream(this, requestor, modStamp, timeStamp), this); } + + @Override + public String getDetectedLineSeparator() { + if (getFlagInt(SYSTEM_LINE_SEPARATOR_DETECTED)) { + return LineSeparator.getSystemLineSeparator().getSeparatorString(); + } + return super.getDetectedLineSeparator(); + } + + @Override + public void setDetectedLineSeparator(String separator) { + boolean hasSystemSeparator = LineSeparator.getSystemLineSeparator().getSeparatorString().equals(separator); + setFlagInt(SYSTEM_LINE_SEPARATOR_DETECTED, hasSystemSeparator); + super.setDetectedLineSeparator(hasSystemSeparator ? null : separator); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java index 2d5b5195dad6..e0772bc3e4fc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.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. @@ -52,14 +52,15 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile { private static final Key<String> SYMLINK_TARGET = Key.create("local.vfs.symlink.target"); + private static final int IS_WRITABLE_FLAG = 0x01000000; + private static final int IS_HIDDEN_FLAG = 0x02000000; + private static final int INDEXED_FLAG = 0x04000000; + static final int CHILDREN_CACHED = 0x08000000; // makes sense for directory only private static final int DIRTY_FLAG = 0x10000000; private static final int IS_SYMLINK_FLAG = 0x20000000; private static final int HAS_SYMLINK_FLAG = 0x40000000; private static final int IS_SPECIAL_FLAG = 0x80000000; - private static final int IS_WRITABLE_FLAG = 0x01000000; - private static final int IS_HIDDEN_FLAG = 0x02000000; - private static final int INDEXED_FLAG = 0x04000000; - static final int CHILDREN_CACHED = 0x08000000; + static final int SYSTEM_LINE_SEPARATOR_DETECTED = CHILDREN_CACHED; // makes sense only for non-directory file private static final int ALL_FLAGS_MASK = DIRTY_FLAG | IS_SYMLINK_FLAG | HAS_SYMLINK_FLAG | IS_SPECIAL_FLAG | IS_WRITABLE_FLAG | IS_HIDDEN_FLAG | INDEXED_FLAG | CHILDREN_CACHED; @@ -68,6 +69,10 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile { private volatile VirtualDirectoryImpl myParent; private volatile int myFlags; private volatile int myId; + + static { + assert (~ALL_FLAGS_MASK) == LocalTimeCounter.TIME_MASK; + } public VirtualFileSystemEntry(int nameId, VirtualDirectoryImpl parent, int id, @PersistentFS.Attributes int attributes) { myParent = parent; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java index c1c7cd6371fb..de9a6d51b498 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -543,12 +543,12 @@ public class FSRecords implements Forceable { private static class ContentHashesDescriptor implements KeyDescriptor<byte[]>, DifferentSerializableBytesImplyNonEqualityPolicy { @Override - public void save(DataOutput out, byte[] value) throws IOException { + public void save(@NotNull DataOutput out, byte[] value) throws IOException { out.write(value); } @Override - public byte[] read(DataInput in) throws IOException { + public byte[] read(@NotNull DataInput in) throws IOException { byte[] b = new byte[SIGNATURE_LENGTH]; in.readFully(b); return b; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeGlassPaneImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeGlassPaneImpl.java index 09de7d3ddcfb..7719e784a4ee 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeGlassPaneImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeGlassPaneImpl.java @@ -52,7 +52,12 @@ public class IdeGlassPaneImpl extends JPanel implements IdeGlassPaneEx, IdeEvent private Cursor myLastOriginalCursor; private MouseEvent myPrevPressEvent; - private JPanel myFocusProxy = new JPanel(); + private JPanel myFocusProxy = new JPanel(){ + @Override + public String toString() { + return "FocusProxy"; + } + }; public IdeGlassPaneImpl(JRootPane rootPane) { myRootPane = rootPane; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java index 9be7a9245544..5103ce761935 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java @@ -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,10 +17,7 @@ package com.intellij.openapi.wm.impl.status; import com.intellij.ide.util.GotoLineNumberDialog; import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorFactory; -import com.intellij.openapi.editor.LogicalPosition; -import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.*; import com.intellij.openapi.fileEditor.FileEditorManagerEvent; import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; @@ -33,6 +30,7 @@ import org.jetbrains.annotations.NotNull; import java.awt.*; import java.awt.event.MouseEvent; +import java.util.List; public class PositionPanel extends EditorBasedWidget implements StatusBarWidget.Multiframe, StatusBarWidget.TextPresentation, CaretListener, SelectionListener { private String myText; @@ -124,6 +122,16 @@ public class PositionPanel extends EditorBasedWidget implements StatusBarWidget. updatePosition(e.getEditor()); } + @Override + public void caretAdded(CaretEvent e) { + updatePosition(e.getEditor()); + } + + @Override + public void caretRemoved(CaretEvent e) { + updatePosition(e.getEditor()); + } + private void updatePosition(final Editor editor) { if (editor == null) { myText = ""; @@ -157,12 +165,23 @@ public class PositionPanel extends EditorBasedWidget implements StatusBarWidget. ); } else { - LogicalPosition caret = editor.getCaretModel().getLogicalPosition(); - - appendLogicalPosition(caret, message); - if (selectionModel.hasSelection()) { - int len = Math.abs(selectionModel.getSelectionStart() - selectionModel.getSelectionEnd()); - if (len != 0) message.append("/").append(len); + List<Caret> carets = editor.getCaretModel().getAllCarets(); + if (carets.size() > 1) { + message.append(carets.size()).append(" carets ("); + appendLogicalPosition(carets.get(0).getLogicalPosition(), message); + message.append('-'); + appendLogicalPosition(carets.get(carets.size() - 1).getLogicalPosition(), message); + message.append(')'); + } + else { + Caret caret = carets.get(0); + LogicalPosition caretPosition = caret.getLogicalPosition(); + + appendLogicalPosition(caretPosition, message); + if (caret.hasSelection()) { + int len = Math.abs(caret.getSelectionStart() - caret.getSelectionEnd()); + if (len != 0) message.append("/").append(len); + } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToolWindowsWidget.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToolWindowsWidget.java index d4477a330542..8fd1559c61b1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToolWindowsWidget.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToolWindowsWidget.java @@ -72,8 +72,13 @@ class ToolWindowsWidget extends JLabel implements CustomStatusBarWidget, StatusB @Override public boolean dispatch(AWTEvent e) { if (e instanceof MouseEvent) { + MouseEvent mouseEvent = (MouseEvent)e; + if (mouseEvent.getComponent() == null || !SwingUtilities.isDescendingFrom(mouseEvent.getComponent(), SwingUtilities.getWindowAncestor(ToolWindowsWidget.this))) { + return false; + } + if (e.getID() == MouseEvent.MOUSE_MOVED && isShowing()) { - Point p = ((MouseEvent)e).getLocationOnScreen(); + Point p = mouseEvent.getLocationOnScreen(); Point screen = ToolWindowsWidget.this.getLocationOnScreen(); if (new Rectangle(screen.x - 4, screen.y - 2, getWidth() + 4, getHeight() + 4).contains(p)) { mouseEntered(); @@ -85,7 +90,7 @@ class ToolWindowsWidget extends JLabel implements CustomStatusBarWidget, StatusB } } else if (e.getID() == MouseEvent.MOUSE_EXITED) { //mouse exits WND - mouseExited(((MouseEvent)e).getLocationOnScreen()); + mouseExited(mouseEvent.getLocationOnScreen()); } } return false; diff --git a/platform/platform-impl/src/com/intellij/remote/MutableRemoteCredentials.java b/platform/platform-impl/src/com/intellij/remote/MutableRemoteCredentials.java new file mode 100644 index 000000000000..5f8d33b8302b --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/MutableRemoteCredentials.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2013 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.remote; + +import org.jetbrains.annotations.Nullable; + +/** + * @author traff + */ +public interface MutableRemoteCredentials extends RemoteCredentials { + void setHost(String host); + + void setPort(int port); + + void setUserName(String userName); + + void setPassword(@Nullable String password); + + void setStorePassword(boolean storePassword); + + void setStorePassphrase(boolean storePassphrase); + + void setAnonymous(boolean anonymous); + + void setPrivateKeyFile(String privateKeyFile); + + void setKnownHostsFile(String knownHostsFile); + + void setPassphrase(@Nullable String passphrase); + + void setUseKeyPair(boolean useKeyPair); +} diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteCancelledException.java b/platform/platform-impl/src/com/intellij/remote/RemoteCancelledException.java new file mode 100644 index 000000000000..da38b1a56fa7 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteCancelledException.java @@ -0,0 +1,10 @@ +package com.intellij.remote; + +/** + * @author traff + */ +public class RemoteCancelledException extends RemoteSdkException { + public RemoteCancelledException(String s) { + super(s); + } +} diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteConnectionCredentialsWrapper.java b/platform/platform-impl/src/com/intellij/remote/RemoteConnectionCredentialsWrapper.java new file mode 100644 index 000000000000..a90f4a4df214 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteConnectionCredentialsWrapper.java @@ -0,0 +1,170 @@ +/* + * 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. + * 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.remote; + +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolderBase; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; + +/** + * @author traff + */ +public class RemoteConnectionCredentialsWrapper { + public static final String VAGRANT_PREFIX = "vagrant://"; + public static final String SFTP_DEPLOYMENT_PREFIX = "sftp://"; + + public final Key<VagrantBasedCredentialsHolder> VAGRANT_BASED_CREDENTIALS = Key.create("VAGRANT_BASED_CREDENTIALS"); + public final Key<WebDeploymentCredentialsHolder> WEB_DEPLOYMENT_BASED_CREDENTIALS = Key.create("WEB_DEPLOYMENT_BASED_CREDENTIALS"); + + public final Key<RemoteCredentialsHolder> PLAIN_SSH_CREDENTIALS = Key.create("PLAIN_SSH_CREDENTIALS"); + + private UserDataHolderBase myCredentialsTypeHolder = new UserDataHolderBase(); + + public void setVagrantConnectionType(VagrantBasedCredentialsHolder vagrantBasedCredentials) { + myCredentialsTypeHolder.putUserData(VAGRANT_BASED_CREDENTIALS, vagrantBasedCredentials); + } + + + private VagrantBasedCredentialsHolder getVagrantCredentials() { + return myCredentialsTypeHolder.getUserData(VAGRANT_BASED_CREDENTIALS); + } + + public void setPlainSshCredentials(RemoteCredentialsHolder credentials) { + myCredentialsTypeHolder.putUserData(PLAIN_SSH_CREDENTIALS, credentials); + } + + private RemoteCredentialsHolder getPlainSshCredentials() { + return myCredentialsTypeHolder.getUserData(PLAIN_SSH_CREDENTIALS); + } + + + public void setWebDeploymentCredentials(WebDeploymentCredentialsHolder webDeploymentCredentials) { + myCredentialsTypeHolder.putUserData(WEB_DEPLOYMENT_BASED_CREDENTIALS, webDeploymentCredentials); + } + + private WebDeploymentCredentialsHolder getWebDeploymentCredentials() { + return myCredentialsTypeHolder.getUserData(WEB_DEPLOYMENT_BASED_CREDENTIALS); + } + + private boolean isVagrantConnection() { + return getVagrantCredentials() != null; + } + + private boolean isPlainSshConnection() { + return getPlainSshCredentials() != null; + } + + private boolean isWebDeploymentConnection() { + return getWebDeploymentCredentials() != null; + } + + + public Object getConnectionKey() { + if (isVagrantConnection()) { + return getVagrantCredentials(); + } + else if (isPlainSshConnection()) { + return getPlainSshCredentials(); + } + else if (isWebDeploymentConnection()) { + return getWebDeploymentCredentials(); + } + else { + throw unknownConnectionType(); + } + } + + public void save(final Element rootElement) { + switchType(new RemoteSdkConnectionAcceptor() { + @Override + public void ssh(RemoteCredentialsHolder cred) { + cred.save(rootElement); + } + + @Override + public void vagrant(VagrantBasedCredentialsHolder cred) { + cred.save(rootElement); + } + + @Override + public void deployment(WebDeploymentCredentialsHolder cred) { + cred.save(rootElement); + } + }); + } + + public static IllegalStateException unknownConnectionType() { + return new IllegalStateException("Unknown connection type"); //TODO + } + + public void copyTo(RemoteConnectionCredentialsWrapper copy) { + copy.myCredentialsTypeHolder = new UserDataHolderBase(); + copy.setPlainSshCredentials(getPlainSshCredentials()); + copy.setVagrantConnectionType(getVagrantCredentials()); + copy.setWebDeploymentCredentials(getWebDeploymentCredentials()); + } + + public String getId() { + if (isVagrantConnection()) { + @NotNull VagrantBasedCredentialsHolder cred = getVagrantCredentials(); + + return VAGRANT_PREFIX + cred.getVagrantFolder(); + } + else if (isPlainSshConnection()) { + RemoteCredentials cred = getPlainSshCredentials(); + + return constructSshCredentialsFullPath(cred); + } + else if (isWebDeploymentConnection()) { + WebDeploymentCredentialsHolder cred = getWebDeploymentCredentials(); + return constructSftpCredentialsFullPath(cred.getSshCredentials()); + } + else { + throw unknownConnectionType(); + } + } + + private static String constructSftpCredentialsFullPath(RemoteCredentials cred) { + return SFTP_DEPLOYMENT_PREFIX + cred.getUserName() + "@" + cred.getHost() + ":" + cred.getPort(); + } + + + public static String constructSshCredentialsFullPath(RemoteCredentials cred) { + return RemoteSdkCredentialsHolder.SSH_PREFIX + cred.getUserName() + "@" + cred.getHost() + ":" + cred.getPort(); + } + + public void switchType(RemoteSdkConnectionAcceptor acceptor) { + if (isVagrantConnection()) { + acceptor.vagrant(getVagrantCredentials()); + } + else if (isPlainSshConnection()) { + acceptor.ssh(getPlainSshCredentials()); + } + else if (isWebDeploymentConnection()) { + acceptor.deployment(getWebDeploymentCredentials()); + } + else { + throw unknownConnectionType(); + } + } + + public interface RemoteSdkConnectionAcceptor { + void ssh(RemoteCredentialsHolder cred); + void vagrant(VagrantBasedCredentialsHolder cred); + void deployment(WebDeploymentCredentialsHolder cred); + } +} diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteCredentials.java b/platform/platform-impl/src/com/intellij/remote/RemoteCredentials.java new file mode 100644 index 000000000000..74f1be780ea8 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteCredentials.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2013 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.remote; + +import com.intellij.util.xmlb.annotations.Transient; + +/** + * @author traff + */ +public interface RemoteCredentials { + String getHost(); + + int getPort(); + + @Transient + String getUserName(); + + String getPassword(); + + @Transient + String getPassphrase(); + + boolean isUseKeyPair(); + + boolean isAnonymous(); + + String getPrivateKeyFile(); + + boolean isStorePassword(); + + boolean isStorePassphrase(); + + String getKnownHostsFile(); +} diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remote/RemoteCredentialsHolder.java new file mode 100644 index 000000000000..5f5efb7276ae --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteCredentialsHolder.java @@ -0,0 +1,260 @@ +/* + * Copyright 2000-2013 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.remote; + +import com.intellij.openapi.util.PasswordUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.remote.MutableRemoteCredentials; +import com.intellij.remote.RemoteCredentials; +import com.intellij.remote.RemoteSdkCredentials; +import com.intellij.util.xmlb.annotations.Transient; +import org.jdom.Element; +import org.jetbrains.annotations.Nullable; + +/** + * @author michael.golubev + */ +public class RemoteCredentialsHolder implements MutableRemoteCredentials { + + public static final String HOST = "HOST"; + public static final String PORT = "PORT"; + public static final String ANONYMOUS = "ANONYMOUS"; + public static final String USERNAME = "USERNAME"; + public static final String PASSWORD = "PASSWORD"; + public static final String USE_KEY_PAIR = "USE_KEY_PAIR"; + public static final String PRIVATE_KEY_FILE = "PRIVATE_KEY_FILE"; + public static final String KNOWN_HOSTS_FILE = "MY_KNOWN_HOSTS_FILE"; + public static final String PASSPHRASE = "PASSPHRASE"; + + private String myHost; + private int myPort; + private boolean myAnonymous; + private String myUserName; + private String myPassword; + private boolean myUseKeyPair; + private String myPrivateKeyFile; + private String myKnownHostsFile; + private String myPassphrase; + private boolean myStorePassword; + private boolean myStorePassphrase; + + @Override + public String getHost() { + return myHost; + } + + public void setHost(String host) { + myHost = host; + } + + @Override + public int getPort() { + return myPort; + } + + public void setPort(int port) { + myPort = port; + } + + @Override + @Transient + public String getUserName() { + return myUserName; + } + + public void setUserName(String userName) { + myUserName = userName; + } + + @Override + public String getPassword() { + return myPassword; + } + + public void setPassword(String password) { + myPassword = password; + } + + public void setStorePassword(boolean storePassword) { + myStorePassword = storePassword; + } + + public void setStorePassphrase(boolean storePassphrase) { + myStorePassphrase = storePassphrase; + } + + @Override + public boolean isStorePassword() { + return myStorePassword; + } + + @Override + public boolean isStorePassphrase() { + return myStorePassphrase; + } + + @Override + public boolean isAnonymous() { + return myAnonymous; + } + + public void setAnonymous(boolean anonymous) { + myAnonymous = anonymous; + } + + @Override + public String getPrivateKeyFile() { + return myPrivateKeyFile; + } + + public void setPrivateKeyFile(String privateKeyFile) { + myPrivateKeyFile = privateKeyFile; + } + + @Override + public String getKnownHostsFile() { + return myKnownHostsFile; + } + + public void setKnownHostsFile(String knownHostsFile) { + myKnownHostsFile = knownHostsFile; + } + + @Override + @Transient + public String getPassphrase() { + return myPassphrase; + } + + public void setPassphrase(String passphrase) { + myPassphrase = passphrase; + } + + @Override + public boolean isUseKeyPair() { + return myUseKeyPair; + } + + public void setUseKeyPair(boolean useKeyPair) { + myUseKeyPair = useKeyPair; + } + + public String getSerializedUserName() { + if (myAnonymous || myUserName == null) return ""; + return myUserName; + } + + public void setSerializedUserName(String userName) { + if (StringUtil.isEmpty(userName)) { + myUserName = null; + } + else { + myUserName = userName; + } + } + + public String getSerializedPassword() { + if (myAnonymous) return ""; + + if (myStorePassword) { + return PasswordUtil.encodePassword(myPassword); + } + else { + return ""; + } + } + + public void setSerializedPassword(String serializedPassword) { + if (!StringUtil.isEmpty(serializedPassword)) { + myPassword = PasswordUtil.decodePassword(serializedPassword); + myStorePassword = true; + } + else { + myPassword = null; + } + } + + @Nullable + public String getSerializedPassphrase() { + if (myStorePassphrase) { + return PasswordUtil.encodePassword(myPassphrase); + } + else { + return ""; + } + } + + public void setSerializedPassphrase(String serializedPassphrase) { + if (!StringUtil.isEmpty(serializedPassphrase)) { + myPassphrase = PasswordUtil.decodePassword(serializedPassphrase); + myStorePassphrase = true; + } + else { + myPassphrase = null; + myStorePassphrase = false; + } + } + + public void copyRemoteCredentialsTo(RemoteSdkCredentials to) { + to.setHost(getHost()); + to.setPort(getPort()); + to.setAnonymous(isAnonymous()); + to.setUserName(getUserName()); + to.setPassword(getPassword()); + to.setUseKeyPair(isUseKeyPair()); + to.setPrivateKeyFile(getPrivateKeyFile()); + to.setKnownHostsFile(getKnownHostsFile()); + to.setStorePassword(isStorePassword()); + to.setStorePassphrase(isStorePassphrase()); + } + + public void load(Element element) { + setHost(element.getAttributeValue(HOST)); + setPort(StringUtil.parseInt(element.getAttributeValue(PORT), 22)); + setAnonymous(StringUtil.parseBoolean(element.getAttributeValue(ANONYMOUS), false)); + setSerializedUserName(element.getAttributeValue(USERNAME)); + setSerializedPassword(element.getAttributeValue(PASSWORD)); + setPrivateKeyFile(StringUtil.nullize(element.getAttributeValue(PRIVATE_KEY_FILE))); + setKnownHostsFile(StringUtil.nullize(element.getAttributeValue(KNOWN_HOSTS_FILE))); + setSerializedPassphrase(element.getAttributeValue(PASSPHRASE)); + setUseKeyPair(StringUtil.parseBoolean(element.getAttributeValue(USE_KEY_PAIR), false)); + } + + public void save(Element rootElement) { + rootElement.setAttribute(HOST, StringUtil.notNullize(getHost())); + rootElement.setAttribute(PORT, Integer.toString(getPort())); + rootElement.setAttribute(ANONYMOUS, Boolean.toString(isAnonymous())); + rootElement.setAttribute(USERNAME, getSerializedUserName()); + rootElement.setAttribute(PASSWORD, getSerializedPassword()); + rootElement.setAttribute(PRIVATE_KEY_FILE, StringUtil.notNullize(getPrivateKeyFile())); + rootElement.setAttribute(KNOWN_HOSTS_FILE, StringUtil.notNullize(getKnownHostsFile())); + rootElement.setAttribute(PASSPHRASE, getSerializedPassphrase()); + rootElement.setAttribute(USE_KEY_PAIR, Boolean.toString(isUseKeyPair())); + } + + public void copyFrom(RemoteCredentials from) { + setHost(from.getHost()); + setPort(from.getPort()); + setAnonymous(from.isAnonymous()); + setUserName(from.getUserName()); + setPassword(from.getPassword()); + setUseKeyPair(from.isUseKeyPair()); + setPrivateKeyFile(from.getPrivateKeyFile()); + setKnownHostsFile(from.getKnownHostsFile()); + setStorePassword(from.isStorePassword()); + setStorePassphrase(from.isStorePassphrase()); + } +} diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteFile.java b/platform/platform-impl/src/com/intellij/remote/RemoteFile.java new file mode 100644 index 000000000000..4a2e11379364 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteFile.java @@ -0,0 +1,110 @@ +package com.intellij.remote; + +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author traff + */ +public class RemoteFile { + + private final boolean myWin; + private final String myPath; + + public RemoteFile(@NotNull String path, boolean isWin) { + myPath = toSystemDependent(path, isWin); + myWin = isWin; + } + + public RemoteFile(@NotNull String parent, String child) { + this(resolveChild(parent, child, isWindowsPath(parent)), isWindowsPath(parent)); + } + + public RemoteFile(@NotNull String parent, String child, boolean isWin) { + this(resolveChild(parent, child, isWin), isWin); + } + + @Nullable + public String getName() { + int ind = myPath.lastIndexOf(getSeparator(myWin)); + if (ind != -1 && ind < myPath.length() - 1) { //not last char + return myPath.substring(ind + 1); + } + else { + return null; + } + } + + private static String resolveChild(@NotNull String parent, @NotNull String child, boolean win) { + String separator = getSeparator(win); + + String path; + if (parent.endsWith(separator)) { + path = parent + child; + } + else { + path = parent + separator + child; + } + return path; + } + + private static String getSeparator(boolean win) { + String separator; + if (win) { + separator = "\\"; + } + else { + separator = "/"; + } + return separator; + } + + + public String getPath() { + return myPath; + } + + public boolean isWin() { + return isWindowsPath(myPath); + } + + public static boolean isWindowsPath(@NotNull String path) { + path = RemoteSdkCredentialsHolder.getInterpreterPathFromFullPath(path); + + return (path.length() > 1 && path.charAt(1) == ':'); + } + + private static String toSystemDependent(@NotNull String path, boolean isWin) { + char separator = isWin ? '\\' : '/'; + return FileUtil.toSystemIndependentName(path).replace('/', separator); + } + + public static RemoteFileBuilder detectSystemByPath(@NotNull String path) { + return new RemoteFileBuilder(isWindowsPath(path)); + } + + public static RemoteFile createRemoteFile(String path, String script) { + return detectSystemByPath(path).createRemoteFile(path, script); + } + + public static RemoteFile createRemoteFile(final String path, final String script, final boolean isWindows) { + return new RemoteFileBuilder(isWindows).createRemoteFile(path, script); + } + + public static class RemoteFileBuilder { + private final boolean isWin; + + private RemoteFileBuilder(boolean win) { + isWin = win; + } + + public RemoteFile createRemoteFile(String path) { + return new RemoteFile(path, isWin); + } + + public RemoteFile createRemoteFile(String path, String child) { + return new RemoteFile(path, child, isWin); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteProcessHandlerBase.java b/platform/platform-impl/src/com/intellij/remote/RemoteProcessHandlerBase.java new file mode 100644 index 000000000000..efeb9bf176e6 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteProcessHandlerBase.java @@ -0,0 +1,20 @@ +package com.intellij.remote; + +import com.intellij.openapi.util.Pair; +import com.intellij.remote.RemoteSdkException; +import com.intellij.util.PathMappingSettings; + +import java.util.List; + +/** + * @author traff + */ +public interface RemoteProcessHandlerBase { + PathMappingSettings getMappingSettings(); + + Pair<String, Integer> obtainRemoteSocket() throws RemoteSdkException; + + void addRemoteForwarding(int remotePort, int localPort); + + List<PathMappingSettings.PathMapping> getFileMappings(); +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkAdditionalData2.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkAdditionalData.java index 92ec30233a6c..4cb6707f7577 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkAdditionalData2.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkAdditionalData.java @@ -13,17 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.remotesdk2; +package com.intellij.remote; import com.intellij.openapi.projectRoots.SdkAdditionalData; -import com.intellij.remotesdk.RemoteSdkCredentials; -import com.intellij.remotesdk.RemoteSdkCredentialsHolder; -import com.intellij.remotesdk.RemoteSdkProperties; +import org.jetbrains.annotations.NotNull; /** * @author traff */ -public interface RemoteSdkAdditionalData2<T extends RemoteSdkCredentials> +public interface RemoteSdkAdditionalData<T extends RemoteSdkCredentials> extends SdkAdditionalData, RemoteSdkProducer<T>, RemoteSdkProperties { void completeInitialization(); @@ -33,9 +31,13 @@ public interface RemoteSdkAdditionalData2<T extends RemoteSdkCredentials> String getFullInterpreterPath(); + void setVagrantConnectionType(@NotNull VagrantBasedCredentialsHolder vagrantBasedCredentials); + /** * This method switches to use of ssh-credentials based data * @param credentials credentials that specify connection */ - void setSshCredentials(RemoteSdkCredentialsHolder credentials); + void setSshCredentials(@NotNull RemoteCredentialsHolder credentials); + + void setDeploymentConnectionType(@NotNull WebDeploymentCredentialsHolder credentials); } diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentials.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentials.java new file mode 100644 index 000000000000..876f82771025 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentials.java @@ -0,0 +1,11 @@ +package com.intellij.remote; + +import com.intellij.remote.MutableRemoteCredentials; +import com.intellij.remote.RemoteSdkProperties; + +/** + * @author traff + */ +public interface RemoteSdkCredentials extends MutableRemoteCredentials, RemoteSdkProperties { + String getFullInterpreterPath(); +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentialsBuilder.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java index 57ea1136527b..59e9cf02d7ba 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentialsBuilder.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.remotesdk; +package com.intellij.remote; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsHolder.java index 88663598f9c6..e936686e0840 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentialsHolder.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsHolder.java @@ -1,11 +1,9 @@ -package com.intellij.remotesdk; +package com.intellij.remote; -import com.intellij.openapi.util.text.StringUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.LinkedList; import java.util.List; /** @@ -13,11 +11,6 @@ import java.util.List; */ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implements RemoteSdkCredentials { public static final String SSH_PREFIX = "ssh://"; - private static final String INTERPRETER_PATH = "INTERPRETER_PATH"; - private static final String HELPERS_PATH = "HELPERS_PATH"; - private static final String REMOTE_ROOTS = "REMOTE_ROOTS"; - private static final String REMOTE_PATH = "REMOTE_PATH"; - private static final String INITIALIZED = "INITIALIZED"; @NotNull private final RemoteSdkPropertiesHolder myRemoteSdkProperties; @@ -30,7 +23,6 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen return SSH_PREFIX + cred.getUserName() + "@" + cred.getHost() + ":" + cred.getPort() + cred.getInterpreterPath(); } - /** * Extracts interpreter path from full path generated by method getFullInterpreterPath * Returns fullPath as fallback @@ -118,7 +110,7 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen @Override public String getFullInterpreterPath() { - return myRemoteSdkProperties.getFullInterpreterPath(); + return constructSshCredentialsSdkFullPath(this); } @Override @@ -127,6 +119,11 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen } @Override + public String getSdkId() { + return myRemoteSdkProperties.getSdkId(); + } + + @Override public boolean isInitialized() { return myRemoteSdkProperties.isInitialized(); } @@ -138,64 +135,27 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen public static boolean isRemoteSdk(@Nullable String path) { if (path != null) { - return path.startsWith(SSH_PREFIX); + return path.startsWith(SSH_PREFIX) || path.startsWith(RemoteConnectionCredentialsWrapper.VAGRANT_PREFIX) || + path.startsWith(RemoteConnectionCredentialsWrapper.SFTP_DEPLOYMENT_PREFIX); } else { return false; } } - public void loadRemoteSdkCredentials(Element element) { - setHost(element.getAttributeValue(HOST)); - setPort(StringUtil.parseInt(element.getAttributeValue(PORT), 22)); - setAnonymous(StringUtil.parseBoolean(element.getAttributeValue(ANONYMOUS), false)); - setSerializedUserName(element.getAttributeValue(USERNAME)); - setSerializedPassword(element.getAttributeValue(PASSWORD)); - setPrivateKeyFile(StringUtil.nullize(element.getAttributeValue(PRIVATE_KEY_FILE))); - setKnownHostsFile(StringUtil.nullize(element.getAttributeValue(KNOWN_HOSTS_FILE))); - setSerializedPassphrase(element.getAttributeValue(PASSPHRASE)); - setUseKeyPair(StringUtil.parseBoolean(element.getAttributeValue(USE_KEY_PAIR), false)); - - setInterpreterPath(StringUtil.nullize(element.getAttributeValue(INTERPRETER_PATH))); - setHelpersPath(StringUtil.nullize(element.getAttributeValue(HELPERS_PATH))); - setRemoteRoots(loadStringsList(element, REMOTE_ROOTS, REMOTE_PATH)); + @Override + public void load(Element element) { + super.load(element); - setInitialized(StringUtil.parseBoolean(element.getAttributeValue(INITIALIZED), true)); + myRemoteSdkProperties.load(element); } - protected static List<String> loadStringsList(Element element, String rootName, String attrName) { - final List<String> paths = new LinkedList<String>(); - if (element != null) { - @NotNull final List list = element.getChildren(rootName); - for (Object o : list) { - paths.add(((Element)o).getAttribute(attrName).getValue()); - } - } - return paths; - } + @Override + public void save(Element rootElement) { + super.save(rootElement); - public void saveRemoteSdkData(Element rootElement) { - rootElement.setAttribute(HOST, StringUtil.notNullize(getHost())); - rootElement.setAttribute(PORT, Integer.toString(getPort())); - rootElement.setAttribute(ANONYMOUS, Boolean.toString(isAnonymous())); - rootElement.setAttribute(USERNAME, getSerializedUserName()); - rootElement.setAttribute(PASSWORD, getSerializedPassword()); - rootElement.setAttribute(PRIVATE_KEY_FILE, StringUtil.notNullize(getPrivateKeyFile())); - rootElement.setAttribute(KNOWN_HOSTS_FILE, StringUtil.notNullize(getKnownHostsFile())); - rootElement.setAttribute(PASSPHRASE, getSerializedPassphrase()); - rootElement.setAttribute(USE_KEY_PAIR, Boolean.toString(isUseKeyPair())); - - rootElement.setAttribute(INTERPRETER_PATH, StringUtil.notNullize(getInterpreterPath())); - rootElement.setAttribute(HELPERS_PATH, StringUtil.notNullize(getHelpersPath())); - - rootElement.setAttribute(INITIALIZED, Boolean.toString(isInitialized())); - - for (String remoteRoot : getRemoteRoots()) { - final Element child = new Element(REMOTE_ROOTS); - child.setAttribute(REMOTE_PATH, remoteRoot); - rootElement.addContent(child); - } + myRemoteSdkProperties.save(rootElement); } @@ -268,8 +228,8 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen '}'; } - public void copyTo(RemoteSdkCredentialsHolder to) { - super.copyTo(to); + public void copyRemoteSdkCredentialsTo(RemoteSdkCredentialsHolder to) { + super.copyRemoteCredentialsTo(to); myRemoteSdkProperties.copyTo(to.getRemoteSdkProperties()); } } diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkException.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkException.java new file mode 100644 index 000000000000..fd6f5440b782 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkException.java @@ -0,0 +1,49 @@ +package com.intellij.remote; + +import com.intellij.execution.ExecutionException; + +import java.net.NoRouteToHostException; + +/** + * @author traff + */ +public class RemoteSdkException extends ExecutionException { + private final boolean myNoRouteToHost; + private final boolean myAuthFailed; + + public RemoteSdkException(String s, Throwable throwable) { + super(s, throwable); + myNoRouteToHost = throwable instanceof NoRouteToHostException; + myAuthFailed = false; + } + + public RemoteSdkException(String s) { + super(s); + myAuthFailed = false; + myNoRouteToHost = false; + } + + public boolean isNoRouteToHost() { + return myNoRouteToHost; + } + + public boolean isAuthFailed() { + return myAuthFailed; + } + + public String getMessage() { + if (myNoRouteToHost) { + return getCause().getMessage(); + } + else if (myAuthFailed) { + return "Authentication failed"; + } + else { + return super.getMessage(); + } + } + + public static RemoteSdkException cantObtainRemoteCredentials(Throwable e) { + return new RemoteSdkException("Cant obtain remote credentials", e); + } +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkFactory2.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkFactory.java index cc3d06af7770..dc28679937fe 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkFactory2.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkFactory.java @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.remotesdk2; +package com.intellij.remote; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.remotesdk.RemoteInterpreterException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,9 +26,9 @@ import java.util.Collection; /** * @author traff */ -public interface RemoteSdkFactory2<T extends RemoteSdkAdditionalData2> { +public interface RemoteSdkFactory<T extends RemoteSdkAdditionalData> { Sdk createRemoteSdk(@Nullable Project project, @NotNull T data, @Nullable String sdkName, Collection<Sdk> existingSdks) - throws RemoteInterpreterException; + throws RemoteSdkException; Sdk createUnfinished(T data, Collection<Sdk> existingSdks); diff --git a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkProducer.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkProducer.java index 72c585b642cd..cd5c00ed9e2a 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk2/RemoteSdkProducer.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkProducer.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.remotesdk2; +package com.intellij.remote; -import com.intellij.remotesdk.RemoteSdkCredentials; import com.intellij.util.Consumer; /** @@ -24,7 +23,7 @@ import com.intellij.util.Consumer; public interface RemoteSdkProducer<T extends RemoteSdkCredentials> { T getRemoteSdkCredentials() throws InterruptedException; - void produceRemoteSdkCredentials(Consumer<T> remoteSdkConsumer); + void produceRemoteSdkCredentials(Consumer<T> remoteSdkCredentialsConsumer); Object getRemoteSdkDataKey(); } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkProperties.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkProperties.java index 5e98352accf6..7d132578a6d4 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkProperties.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkProperties.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.remotesdk; +package com.intellij.remote; import java.util.List; @@ -43,10 +43,10 @@ public interface RemoteSdkProperties { void setHelpersVersionChecked(boolean helpersVersionChecked); - String getFullInterpreterPath(); - void setSdkId(String sdkId); + String getSdkId(); + @Deprecated boolean isInitialized(); diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkPropertiesHolder.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkPropertiesHolder.java index 11f350ca10c5..bc5fad1e4fff 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkPropertiesHolder.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkPropertiesHolder.java @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.remotesdk; +package com.intellij.remote; + +import com.intellij.openapi.util.JDOMExternalizer; +import com.intellij.openapi.util.text.StringUtil; +import org.jdom.Element; import java.util.ArrayList; import java.util.List; @@ -22,6 +26,12 @@ import java.util.List; * @author traff */ public class RemoteSdkPropertiesHolder implements RemoteSdkProperties { + private static final String INTERPRETER_PATH = "INTERPRETER_PATH"; + private static final String HELPERS_PATH = "HELPERS_PATH"; + private static final String REMOTE_ROOTS = "REMOTE_ROOTS"; + private static final String REMOTE_PATH = "REMOTE_PATH"; + private static final String INITIALIZED = "INITIALIZED"; + private String mySdkId; private String myInterpreterPath; @@ -93,15 +103,14 @@ public class RemoteSdkPropertiesHolder implements RemoteSdkProperties { myHelpersVersionChecked = helpersVersionChecked; } - @Override - public String getFullInterpreterPath() { - return mySdkId; - } - public void setSdkId(String sdkId) { mySdkId = sdkId; } + public String getSdkId() { + return mySdkId; + } + @Override public boolean isInitialized() { return myInitialized; @@ -113,7 +122,7 @@ public class RemoteSdkPropertiesHolder implements RemoteSdkProperties { } - public void copyTo(RemoteSdkPropertiesHolder copy) { + public void copyTo(RemoteSdkProperties copy) { copy.setInterpreterPath(getInterpreterPath()); copy.setHelpersPath(getHelpersPath()); copy.setHelpersVersionChecked(isHelpersVersionChecked()); @@ -122,4 +131,26 @@ public class RemoteSdkPropertiesHolder implements RemoteSdkProperties { copy.setInitialized(isInitialized()); } + + public void save(Element rootElement) { + rootElement.setAttribute(INTERPRETER_PATH, StringUtil.notNullize(getInterpreterPath())); + rootElement.setAttribute(HELPERS_PATH, StringUtil.notNullize(getHelpersPath())); + + rootElement.setAttribute(INITIALIZED, Boolean.toString(isInitialized())); + + for (String remoteRoot : getRemoteRoots()) { + final Element child = new Element(REMOTE_ROOTS); + child.setAttribute(REMOTE_PATH, remoteRoot); + rootElement.addContent(child); + } + } + + public void load(Element element) { + setInterpreterPath(StringUtil.nullize(element.getAttributeValue(INTERPRETER_PATH))); + setHelpersPath(StringUtil.nullize(element.getAttributeValue(HELPERS_PATH))); + + setRemoteRoots(JDOMExternalizer.loadStringsList(element, REMOTE_ROOTS, REMOTE_PATH)); + + setInitialized(StringUtil.parseBoolean(element.getAttributeValue(INITIALIZED), true)); + } } diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSshProcess.java b/platform/platform-impl/src/com/intellij/remote/RemoteSshProcess.java new file mode 100644 index 000000000000..b9090bcd3ee8 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSshProcess.java @@ -0,0 +1,22 @@ +package com.intellij.remote; + +import com.intellij.execution.process.SelfKiller; + +/** + * @author traff + */ +abstract public class RemoteSshProcess extends Process implements SelfKiller { + /** + * Makes host:localPort server which is available on local side available on remote side as localhost:remotePort. + */ + public abstract void addRemoteTunnel(int remotePort, String host, int localPort) throws RemoteSdkException; + + /** + * Makes host:remotePort server which is available on remote side available on local side as localhost:localPort. + */ + public abstract void addLocalTunnel(int localPort, String host, int remotePort) throws RemoteSdkException; + + public abstract boolean hasPty(); + + public abstract boolean sendCtrlC(); +} diff --git a/platform/platform-impl/src/com/intellij/remote/VagrantBasedCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remote/VagrantBasedCredentialsHolder.java new file mode 100644 index 000000000000..d5f867c5836d --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/VagrantBasedCredentialsHolder.java @@ -0,0 +1,51 @@ +/* + * 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. + * 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.remote; + +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; + +/** +* @author traff +*/ +public class VagrantBasedCredentialsHolder { + private static final String VAGRANT_FOLDER = "VAGRANT_FOLDER"; + private String myVagrantFolder; + + public VagrantBasedCredentialsHolder() { + } + + public VagrantBasedCredentialsHolder(@NotNull String folder) { + myVagrantFolder = folder; + } + + public void setVagrantFolder(String vagrantFolder) { + myVagrantFolder = vagrantFolder; + } + + @NotNull + public String getVagrantFolder() { + return myVagrantFolder; + } + + public void load(Element element) { + setVagrantFolder(element.getAttributeValue(VAGRANT_FOLDER)); + } + + public void save(Element element) { + element.setAttribute(VAGRANT_FOLDER, getVagrantFolder()); + } +} diff --git a/platform/platform-impl/src/com/intellij/remote/WebDeploymentCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remote/WebDeploymentCredentialsHolder.java new file mode 100644 index 000000000000..5db969a6592c --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remote/WebDeploymentCredentialsHolder.java @@ -0,0 +1,62 @@ +/* + * 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. + * 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.remote; + +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; + +/** + * @author traff + */ +public class WebDeploymentCredentialsHolder { + public static final String WEB_SERVER_CONFIG_ID = "WEB_SERVER_CONFIG_ID"; + + private String myWebServerConfigId; + private final RemoteCredentialsHolder myRemoteCredentials = new RemoteCredentialsHolder(); + + + public WebDeploymentCredentialsHolder() { + } + + public WebDeploymentCredentialsHolder(@NotNull String webServerConfigId, @NotNull RemoteCredentials remoteCredentials) { + myWebServerConfigId = webServerConfigId; + myRemoteCredentials.copyFrom(remoteCredentials); + } + + @NotNull + public String getWebServerConfigId() { + return myWebServerConfigId; + } + + public void setWebServerConfigId(@NotNull String webServerConfigId) { + myWebServerConfigId = webServerConfigId; + } + + public void load(Element element) { + myRemoteCredentials.load(element); + setWebServerConfigId(element.getAttributeValue(WEB_SERVER_CONFIG_ID)); + } + + public void save(Element element) { + element.setAttribute(WEB_SERVER_CONFIG_ID, getWebServerConfigId()); + + myRemoteCredentials.save(element); + } + + public RemoteCredentials getSshCredentials() { + return myRemoteCredentials; + } +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk/MutableRemoteCredentials.java b/platform/platform-impl/src/com/intellij/remotesdk/MutableRemoteCredentials.java index e52d8d3337fb..0b630fec6a8b 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/MutableRemoteCredentials.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/MutableRemoteCredentials.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. @@ -15,31 +15,9 @@ */ package com.intellij.remotesdk; -import org.jetbrains.annotations.Nullable; - /** + * @deprecated Remove in IDEA 14 * @author traff */ -public interface MutableRemoteCredentials extends RemoteCredentials { - void setHost(String host); - - void setPort(int port); - - void setUserName(String userName); - - void setPassword(@Nullable String password); - - void setStorePassword(boolean storePassword); - - void setStorePassphrase(boolean storePassphrase); - - void setAnonymous(boolean anonymous); - - void setPrivateKeyFile(String privateKeyFile); - - void setKnownHostsFile(String knownHostsFile); - - void setPassphrase(@Nullable String passphrase); - - void setUseKeyPair(boolean useKeyPair); +public interface MutableRemoteCredentials extends com.intellij.remote.MutableRemoteCredentials { } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteCancelledException.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteCancelledException.java index eeded52aad2e..2a249209b8e8 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteCancelledException.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteCancelledException.java @@ -1,9 +1,26 @@ +/* + * 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. + * 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.remotesdk; /** + * @deprecated Remove in IDEA 14 + * * @author traff */ -public class RemoteCancelledException extends RemoteInterpreterException { +public class RemoteCancelledException extends com.intellij.remote.RemoteCancelledException { public RemoteCancelledException(String s) { super(s); } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentials.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentials.java index bb7494044beb..e6be766ca826 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentials.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentials.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. @@ -15,33 +15,10 @@ */ package com.intellij.remotesdk; -import com.intellij.util.xmlb.annotations.Transient; - /** + * @deprecated Remove in IDEA 14 + * * @author traff */ -public interface RemoteCredentials { - String getHost(); - - int getPort(); - - @Transient - String getUserName(); - - String getPassword(); - - @Transient - String getPassphrase(); - - boolean isUseKeyPair(); - - boolean isAnonymous(); - - String getPrivateKeyFile(); - - boolean isStorePassword(); - - boolean isStorePassphrase(); - - String getKnownHostsFile(); +public interface RemoteCredentials extends com.intellij.remote.RemoteCredentials { } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentialsHolder.java index d0e7e97902f2..886052957f32 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentialsHolder.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteCredentialsHolder.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. @@ -15,205 +15,10 @@ */ package com.intellij.remotesdk; -import com.intellij.openapi.util.PasswordUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.xmlb.annotations.Transient; -import org.jetbrains.annotations.Nullable; - /** - * @author michael.golubev + * @deprecated Remove in IDEA 14 + * + * @author traff */ -public class RemoteCredentialsHolder implements MutableRemoteCredentials { - - public static final String HOST = "HOST"; - public static final String PORT = "PORT"; - public static final String ANONYMOUS = "ANONYMOUS"; - public static final String USERNAME = "USERNAME"; - public static final String PASSWORD = "PASSWORD"; - public static final String USE_KEY_PAIR = "USE_KEY_PAIR"; - public static final String PRIVATE_KEY_FILE = "PRIVATE_KEY_FILE"; - public static final String KNOWN_HOSTS_FILE = "MY_KNOWN_HOSTS_FILE"; - public static final String PASSPHRASE = "PASSPHRASE"; - - private String myHost; - private int myPort; - private boolean myAnonymous; - private String myUserName; - private String myPassword; - private boolean myUseKeyPair; - private String myPrivateKeyFile; - private String myKnownHostsFile; - private String myPassphrase; - private boolean myStorePassword; - private boolean myStorePassphrase; - - @Override - public String getHost() { - return myHost; - } - - public void setHost(String host) { - myHost = host; - } - - @Override - public int getPort() { - return myPort; - } - - public void setPort(int port) { - myPort = port; - } - - @Override - @Transient - public String getUserName() { - return myUserName; - } - - public void setUserName(String userName) { - myUserName = userName; - } - - @Override - public String getPassword() { - return myPassword; - } - - public void setPassword(String password) { - myPassword = password; - } - - public void setStorePassword(boolean storePassword) { - myStorePassword = storePassword; - } - - public void setStorePassphrase(boolean storePassphrase) { - myStorePassphrase = storePassphrase; - } - - @Override - public boolean isStorePassword() { - return myStorePassword; - } - - @Override - public boolean isStorePassphrase() { - return myStorePassphrase; - } - - @Override - public boolean isAnonymous() { - return myAnonymous; - } - - public void setAnonymous(boolean anonymous) { - myAnonymous = anonymous; - } - - @Override - public String getPrivateKeyFile() { - return myPrivateKeyFile; - } - - public void setPrivateKeyFile(String privateKeyFile) { - myPrivateKeyFile = privateKeyFile; - } - - @Override - public String getKnownHostsFile() { - return myKnownHostsFile; - } - - public void setKnownHostsFile(String knownHostsFile) { - myKnownHostsFile = knownHostsFile; - } - - @Override - @Transient - public String getPassphrase() { - return myPassphrase; - } - - public void setPassphrase(String passphrase) { - myPassphrase = passphrase; - } - - @Override - public boolean isUseKeyPair() { - return myUseKeyPair; - } - - public void setUseKeyPair(boolean useKeyPair) { - myUseKeyPair = useKeyPair; - } - - public String getSerializedUserName() { - if (myAnonymous || myUserName == null) return ""; - return myUserName; - } - - public void setSerializedUserName(String userName) { - if (StringUtil.isEmpty(userName)) { - myUserName = null; - } - else { - myUserName = userName; - } - } - - public String getSerializedPassword() { - if (myAnonymous) return ""; - - if (myStorePassword) { - return PasswordUtil.encodePassword(myPassword); - } - else { - return ""; - } - } - - public void setSerializedPassword(String serializedPassword) { - if (!StringUtil.isEmpty(serializedPassword)) { - myPassword = PasswordUtil.decodePassword(serializedPassword); - myStorePassword = true; - } - else { - myPassword = null; - } - } - - @Nullable - public String getSerializedPassphrase() { - if (myStorePassphrase) { - return PasswordUtil.encodePassword(myPassphrase); - } - else { - return ""; - } - } - - public void setSerializedPassphrase(String serializedPassphrase) { - if (!StringUtil.isEmpty(serializedPassphrase)) { - myPassphrase = PasswordUtil.decodePassword(serializedPassphrase); - myStorePassphrase = true; - } - else { - myPassphrase = null; - myStorePassphrase = false; - } - } - - public void copyTo(RemoteSdkCredentials to) { - to.setHost(getHost()); - to.setPort(getPort()); - to.setAnonymous(isAnonymous()); - to.setUserName(getUserName()); - to.setPassword(getPassword()); - to.setUseKeyPair(isUseKeyPair()); - to.setPrivateKeyFile(getPrivateKeyFile()); - to.setKnownHostsFile(getKnownHostsFile()); - to.setStorePassword(isStorePassword()); - to.setStorePassphrase(isStorePassphrase()); - } +public class RemoteCredentialsHolder extends com.intellij.remote.RemoteCredentialsHolder { } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteFile.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteFile.java index 51896dbf1213..73274cc0f356 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteFile.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteFile.java @@ -1,110 +1,38 @@ +/* + * 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. + * 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.remotesdk; -import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** + * @deprecated Remove in IDEA 14 + * * @author traff */ -public class RemoteFile { - - private final boolean myWin; - private final String myPath; +public class RemoteFile extends com.intellij.remote.RemoteFile { public RemoteFile(@NotNull String path, boolean isWin) { - myPath = toSystemDependent(path, isWin); - myWin = isWin; + super(path, isWin); } public RemoteFile(@NotNull String parent, String child) { - this(resolveChild(parent, child, isWindowsPath(parent)), isWindowsPath(parent)); + super(parent, child); } public RemoteFile(@NotNull String parent, String child, boolean isWin) { - this(resolveChild(parent, child, isWin), isWin); - } - - @Nullable - public String getName() { - int ind = myPath.lastIndexOf(getSeparator(myWin)); - if (ind != -1 && ind < myPath.length() - 1) { //not last char - return myPath.substring(ind + 1); - } - else { - return null; - } - } - - private static String resolveChild(@NotNull String parent, @NotNull String child, boolean win) { - String separator = getSeparator(win); - - String path; - if (parent.endsWith(separator)) { - path = parent + child; - } - else { - path = parent + separator + child; - } - return path; - } - - private static String getSeparator(boolean win) { - String separator; - if (win) { - separator = "\\"; - } - else { - separator = "/"; - } - return separator; - } - - - public String getPath() { - return myPath; - } - - public boolean isWin() { - return isWindowsPath(myPath); - } - - public static boolean isWindowsPath(@NotNull String path) { - path = RemoteSdkCredentialsHolder.getInterpreterPathFromFullPath(path); - - return (path.length() > 1 && path.charAt(1) == ':'); - } - - private static String toSystemDependent(@NotNull String path, boolean isWin) { - char separator = isWin ? '\\' : '/'; - return FileUtil.toSystemIndependentName(path).replace('/', separator); - } - - public static RemoteFileBuilder detectSystemByPath(@NotNull String path) { - return new RemoteFileBuilder(isWindowsPath(path)); - } - - public static RemoteFile createRemoteFile(String path, String script) { - return detectSystemByPath(path).createRemoteFile(path, script); - } - - public static RemoteFile createRemoteFile(final String path, final String script, final boolean isWindows) { - return new RemoteFileBuilder(isWindows).createRemoteFile(path, script); - } - - public static class RemoteFileBuilder { - private final boolean isWin; - - private RemoteFileBuilder(boolean win) { - isWin = win; - } - - public RemoteFile createRemoteFile(String path) { - return new RemoteFile(path, isWin); - } - - public RemoteFile createRemoteFile(String path, String child) { - return new RemoteFile(path, child, isWin); - } + super(parent, child, isWin); } } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteInterpreterException.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteInterpreterException.java index 0a31e6578cce..b3d3b35b5aa2 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteInterpreterException.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteInterpreterException.java @@ -1,49 +1,29 @@ +/* + * 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. + * 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.remotesdk; -import com.intellij.execution.ExecutionException; - -import java.net.NoRouteToHostException; +import com.intellij.remote.RemoteSdkException; /** + * @deprecated Remove in IDEA 14 + * * @author traff */ -public class RemoteInterpreterException extends ExecutionException { - private final boolean myNoRouteToHost; - private final boolean myAuthFailed; - +public class RemoteInterpreterException extends RemoteSdkException { public RemoteInterpreterException(String s, Throwable throwable) { super(s, throwable); - myNoRouteToHost = throwable instanceof NoRouteToHostException; - myAuthFailed = false; - } - - public RemoteInterpreterException(String s) { - super(s); - myAuthFailed = false; - myNoRouteToHost = false; - } - - public boolean isNoRouteToHost() { - return myNoRouteToHost; - } - - public boolean isAuthFailed() { - return myAuthFailed; - } - - public String getMessage() { - if (myNoRouteToHost) { - return getCause().getMessage(); - } - else if (myAuthFailed) { - return "Authentication failed"; - } - else { - return super.getMessage(); - } - } - - public static RemoteInterpreterException cantObtainRemoteCredentials(Throwable e) { - return new RemoteInterpreterException("Cant obtain remote credentials", e); } } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteProcessHandlerBase.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteProcessHandlerBase.java index c004f8ae211d..a83d2bdc2455 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteProcessHandlerBase.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteProcessHandlerBase.java @@ -1,19 +1,24 @@ +/* + * 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. + * 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.remotesdk; -import com.intellij.openapi.util.Pair; -import com.intellij.util.PathMappingSettings; - -import java.util.List; - /** + * @deprecated Remove in IDEA 14 + * * @author traff */ -public interface RemoteProcessHandlerBase { - PathMappingSettings getMappingSettings(); - - Pair<String, Integer> obtainRemoteSocket() throws RemoteInterpreterException; - - void addRemoteForwarding(int remotePort, int localPort); - - List<PathMappingSettings.PathMapping> getFileMappings(); +public interface RemoteProcessHandlerBase extends com.intellij.remote.RemoteProcessHandlerBase { } diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkAdditionalData.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkAdditionalData.java index d9f1b67bb836..e4c79ed8d7f2 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkAdditionalData.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkAdditionalData.java @@ -1,8 +1,10 @@ package com.intellij.remotesdk; import com.intellij.openapi.projectRoots.SdkAdditionalData; +import com.intellij.remote.RemoteSdkCredentials; /** + * @deprecated Remove in IDEA 14 * @author traff */ public interface RemoteSdkAdditionalData extends RemoteSdkCredentials, SdkAdditionalData { diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentials.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentials.java deleted file mode 100644 index 11f14f05119d..000000000000 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkCredentials.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.intellij.remotesdk; - -/** - * @author traff - */ -public interface RemoteSdkCredentials extends MutableRemoteCredentials, RemoteSdkProperties { -} diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkData.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkData.java new file mode 100644 index 000000000000..d99ea338db00 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkData.java @@ -0,0 +1,26 @@ +/* + * 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. + * 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.remotesdk; + +import com.intellij.remote.RemoteSdkCredentials; + +/** + * @deprecated Remove in IDEA 14 + * + * @author traff + */ +public interface RemoteSdkData extends RemoteSdkCredentials { +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkDataBuilder.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkDataBuilder.java new file mode 100644 index 000000000000..f2dd26589392 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkDataBuilder.java @@ -0,0 +1,26 @@ +/* + * 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. + * 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.remotesdk; + +import com.intellij.remote.RemoteSdkCredentialsBuilder; + +/** + * @deprecated Remove in IDEA 14 + * + * @author traff + */ +public class RemoteSdkDataBuilder extends RemoteSdkCredentialsBuilder { +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkDataHolder.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkDataHolder.java new file mode 100644 index 000000000000..b4f837c72a3f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkDataHolder.java @@ -0,0 +1,30 @@ +/* + * 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. + * 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.remotesdk; + +import com.intellij.remote.RemoteSdkCredentialsHolder; +import org.jetbrains.annotations.NotNull; + +/** + * @deprecated Remove in IDEA 14 + * + * @author traff + */ +public class RemoteSdkDataHolder extends RemoteSdkCredentialsHolder { + public RemoteSdkDataHolder(@NotNull String defaultHelpersDirName) { + super(defaultHelpersDirName); + } +} diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkFactory.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkFactory.java index 86113a5337bf..1934d1aa36a2 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkFactory.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSdkFactory.java @@ -17,6 +17,7 @@ package com.intellij.remotesdk; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.remote.RemoteSdkException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -24,6 +25,7 @@ import java.awt.*; import java.util.Collection; /** + * @deprecated Remove in IDEA 14 * @author traff */ public interface RemoteSdkFactory<T extends RemoteSdkAdditionalData> { diff --git a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSshProcess.java b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSshProcess.java index 35c589719b53..3abe39bd1aba 100644 --- a/platform/platform-impl/src/com/intellij/remotesdk/RemoteSshProcess.java +++ b/platform/platform-impl/src/com/intellij/remotesdk/RemoteSshProcess.java @@ -1,22 +1,23 @@ +/* + * 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. + * 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.remotesdk; -import com.intellij.execution.process.SelfKiller; - /** + * @deprecated Remove in IDEA 14 * @author traff */ -abstract public class RemoteSshProcess extends Process implements SelfKiller { - /** - * Makes host:localPort server which is available on local side available on remote side as localhost:remotePort. - */ - public abstract void addRemoteTunnel(int remotePort, String host, int localPort) throws RemoteInterpreterException; - - /** - * Makes host:remotePort server which is available on remote side available on local side as localhost:localPort. - */ - public abstract void addLocalTunnel(int localPort, String host, int remotePort) throws RemoteInterpreterException; - - public abstract boolean hasPty(); - - public abstract boolean sendCtrlC(); +public abstract class RemoteSshProcess extends com.intellij.remote.RemoteSshProcess { } diff --git a/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java b/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java index c3ba3a3dd834..0070cb0a70e5 100644 --- a/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java +++ b/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.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. @@ -206,6 +206,7 @@ public abstract class AbstractExpandableItemsHandler<KeyType, ComponentType exte if (!myEnabled) return; if (selected == null + || !myComponent.isEnabled() || !myComponent.isShowing() || !myComponent.isFocusOwner() && !processIfUnfocused || isPopup()) { diff --git a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java index 47970514f429..411186ce962d 100644 --- a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java +++ b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java @@ -7,6 +7,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.ide.CopyPasteManager; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; @@ -423,7 +424,7 @@ public abstract class FinderRecursivePanel<T> extends JBSplitter implements Data ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - ApplicationManager.getApplication().runReadAction(new Runnable() { + DumbService.getInstance(getProject()).runReadActionInSmartMode(new Runnable() { @Override public void run() { try { diff --git a/platform/platform-impl/src/com/intellij/ui/SystemNotifications.java b/platform/platform-impl/src/com/intellij/ui/SystemNotifications.java index 08e38637801d..b0d7b371a3e0 100644 --- a/platform/platform-impl/src/com/intellij/ui/SystemNotifications.java +++ b/platform/platform-impl/src/com/intellij/ui/SystemNotifications.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. @@ -15,6 +15,8 @@ */ package com.intellij.ui; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import org.jetbrains.annotations.NotNull; @@ -22,8 +24,14 @@ import org.jetbrains.annotations.NotNull; * @author mike */ public abstract class SystemNotifications { + private static final SystemNotifications NULL = new SystemNotifications() { + @Override + public void notify(@NotNull String notificationName, @NotNull String title, @NotNull String text) { } + }; + public static SystemNotifications getInstance() { - return ServiceManager.getService(SystemNotifications.class); + Application app = ApplicationManager.getApplication(); + return app.isHeadlessEnvironment() || app.isUnitTestMode() ? NULL : ServiceManager.getService(SystemNotifications.class); } public abstract void notify(@NotNull String notificationName, @NotNull String title, @NotNull String text); diff --git a/platform/platform-impl/src/com/intellij/ui/SystemNotificationsImpl.java b/platform/platform-impl/src/com/intellij/ui/SystemNotificationsImpl.java index 597301bb1a2d..d81ea5846148 100644 --- a/platform/platform-impl/src/com/intellij/ui/SystemNotificationsImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/SystemNotificationsImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,7 +83,13 @@ public class SystemNotificationsImpl extends SystemNotifications implements Pers } } catch (Throwable t) { - Logger.getInstance(SystemNotifications.class).error(t); + Logger logger = Logger.getInstance(SystemNotifications.class); + if (logger.isDebugEnabled()) { + logger.debug(t); + } + else { + logger.info(t.getMessage()); + } } return null; diff --git a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java index aac44fcd37a2..1bee208832eb 100755 --- a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java +++ b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java @@ -20,13 +20,13 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.ui.Gray; import com.intellij.ui.JBColor; import com.intellij.util.ui.UIUtil; +import org.jdesktop.swingx.graphics.GraphicsUtilities; +import org.jdesktop.swingx.graphics.ShadowRenderer; import javax.swing.*; import java.awt.*; import java.awt.event.*; -import java.awt.geom.Area; import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; /** @@ -45,9 +45,19 @@ public class SheetController { private JButton[] buttons; private JButton myDefaultButton; private JButton myFocusedButton; + + public int SHADOW_BORDER = 10; + + // SHEET public int SHEET_WIDTH = 400; + public int SHEET_HEIGHT = 150; + // SHEET + shadow + int SHEET_NC_WIDTH = SHEET_WIDTH + SHADOW_BORDER * 2; + int SHEET_NC_HEIGHT = SHEET_HEIGHT + SHADOW_BORDER ; + + private Icon myIcon = AllIcons.Logo_welcomeScreen; private String myResult; @@ -151,9 +161,11 @@ public class SheetController { g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.95f)); g2d.setColor(Gray._225); - Rectangle2D dialog = new Rectangle2D.Double(0,0,mySheetPanel.getBounds().width - 5, mySheetPanel.getBounds().height - 10); + Rectangle2D dialog = new Rectangle2D.Double(SHADOW_BORDER, 0, SHEET_WIDTH, SHEET_HEIGHT); + + paintShadow(g2d); + // draw the sheet background g2d.fill(dialog); - paintShadow(g2d, dialog); } }; @@ -211,21 +223,30 @@ public class SheetController { SHEET_HEIGHT = 20 + headerLabel.getPreferredSize().height + 10 + messageArea.height + 10 + 70; - sheetPanel.setSize(SHEET_WIDTH, SHEET_HEIGHT); + ico.setOpaque(false); ico.setSize(new Dimension(AllIcons.Logo_welcomeScreen.getIconWidth(), AllIcons.Logo_welcomeScreen.getIconHeight())); - ico.setLocation(20, 20); + ico.setLocation(40, 20); sheetPanel.add(ico); - headerLabel.setLocation(120, 20); - messageTextPane.setLocation(120, 20 + headerLabel.getPreferredSize().height + 10); + headerLabel.setLocation(140, 20); + messageTextPane.setLocation(140, 20 + headerLabel.getPreferredSize().height + 10); layoutWithAbsoluteLayout(buttons, sheetPanel); sheetPanel.setFocusCycleRoot(true); + recalculateShadow(); + + sheetPanel.setSize(SHEET_NC_WIDTH, SHEET_NC_HEIGHT ); + return sheetPanel; } + private void recalculateShadow() { + SHEET_NC_WIDTH = SHEET_WIDTH + SHADOW_BORDER * 2; + SHEET_NC_HEIGHT = SHEET_HEIGHT + SHADOW_BORDER; + } + private void layoutWithAbsoluteLayout(JButton[] buttons, JPanel sheetPanel) { layoutButtons(buttons, sheetPanel); @@ -235,31 +256,33 @@ public class SheetController { } } - private void paintShadow(Graphics2D g2d, Rectangle2D dialog) { - Area shadow = new Area(new RoundRectangle2D.Double(0, 0, mySheetPanel.getBounds().width, mySheetPanel.getBounds().height, 10, 10)); - - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.80f)); - - Color color1 = Gray._130; - Color color2 = new JBColor(new Color(130, 130, 130, 0), new Color(130, 130, 130, 0)); - - GradientPaint gp = new GradientPaint( - 0, mySheetPanel.getBounds().height - 10, color1, - 0, mySheetPanel.getBounds().height, color2 ); - - g2d.setPaint(gp); - shadow.subtract(new Area(dialog)); - g2d.fill(shadow); + private void paintShadow(Graphics2D g2d) { + BufferedImage bufferedImage = GraphicsUtilities.createCompatibleTranslucentImage( + SHEET_WIDTH, SHEET_HEIGHT); + + Graphics2D g2 = bufferedImage.createGraphics(); + g2.setColor(JBColor.WHITE); + g2.fillRoundRect(0, 0, SHEET_WIDTH - 1, SHEET_HEIGHT - 1, SHADOW_BORDER, SHADOW_BORDER); + g2.dispose(); + + ShadowRenderer renderer = new ShadowRenderer(); + renderer.setSize(SHADOW_BORDER); + renderer.setOpacity(0.95f); + renderer.setColor(JBColor.BLACK); + BufferedImage shadow = renderer.createShadow(bufferedImage); + g2d.drawImage(shadow, 0, - SHADOW_BORDER, null); + g2d.setBackground(new JBColor(new Color(255, 255, 255, 0), new Color(255, 255, 255, 0))); + g2d.clearRect(SHADOW_BORDER, 0, SHEET_WIDTH, SHEET_HEIGHT); } private void layoutButtons(final JButton[] buttons, JPanel panel) { - int buttonsWidth = 120; + int buttonsWidth = 15 * 2; for (JButton button : buttons) { panel.add(button); button.repaint(); - buttonsWidth = button.getWidth() + 10; + buttonsWidth += button.getPreferredSize().width + 10; } SHEET_WIDTH = Math.max(buttonsWidth, SHEET_WIDTH); @@ -298,7 +321,7 @@ public class SheetController { myOffScreenFrame.add(mySheetPanel); myOffScreenFrame.getRootPane().setDefaultButton(myDefaultButton); - final BufferedImage image = UIUtil.createImage(SHEET_WIDTH, SHEET_HEIGHT, BufferedImage.TYPE_INT_ARGB); + final BufferedImage image = UIUtil.createImage(SHEET_NC_WIDTH, SHEET_NC_HEIGHT, BufferedImage.TYPE_INT_ARGB); mySheetPanel.paint(image.createGraphics()); myOffScreenFrame.dispose(); diff --git a/platform/platform-impl/src/com/intellij/ui/messages/SheetMessage.java b/platform/platform-impl/src/com/intellij/ui/messages/SheetMessage.java index e90078aa7a19..f2249ad89e12 100755 --- a/platform/platform-impl/src/com/intellij/ui/messages/SheetMessage.java +++ b/platform/platform-impl/src/com/intellij/ui/messages/SheetMessage.java @@ -54,13 +54,14 @@ public class SheetMessage { @Override public void paint(Graphics g) { super.paint(g); + } }; myParent = owner; myWindow.setUndecorated(true); - myWindow.setBackground(new JBColor(new Color(0, 0, 0, 0), new Color(0, 0, 0, 0))); + myWindow.setBackground(new JBColor(new Color(0, 0, 0, 0), new Color(0, 0, 0, 0))); myController = new SheetController(this, title, message, icon, buttons, defaultButton, doNotAskOption, focusedButton); @@ -70,7 +71,7 @@ public class SheetMessage { myWindow.setFocusable(true); startAnimation(true); - myWindow.setSize(myController.SHEET_WIDTH, myController.SHEET_HEIGHT); + myWindow.setSize(myController.SHEET_NC_WIDTH, myController.SHEET_NC_HEIGHT); restoreFullscreenButton = couldBeInFullScreen(); if (restoreFullscreenButton) { FullScreenUtilities.setWindowCanFullScreen(myParent, false); @@ -108,24 +109,24 @@ public class SheetMessage { int imageCropOffset = (UIUtil.isRetina()) ? imageHeight * 2 : imageHeight; - g.drawImage(staticImage, 0,0,myController.SHEET_WIDTH,imageHeight, + g.drawImage(staticImage, 0, 0, myController.SHEET_NC_WIDTH,imageHeight, 0, staticImage.getHeight(null) - imageCropOffset, staticImage.getWidth(null) ,staticImage.getHeight(null) ,null); } } }; staticPanel.setOpaque(false); - staticPanel.setSize(myController.SHEET_WIDTH,myController.SHEET_HEIGHT); + staticPanel.setSize(myController.SHEET_NC_WIDTH,myController.SHEET_NC_HEIGHT); myWindow.setContentPane(staticPanel); - Animator myAnimator = new Animator("Roll Down Sheet Animator", myController.SHEET_HEIGHT , + Animator myAnimator = new Animator("Roll Down Sheet Animator", myController.SHEET_NC_HEIGHT , TIME_TO_SHOW_SHEET, false) { @Override public void paintNow(int frame, int totalFrames, int cycle) { setPositionRelativeToParent(); float percentage = (float)frame/(float)totalFrames; - imageHeight = enlarge ? (int)(((float)myController.SHEET_HEIGHT) * percentage): - (int)(myController.SHEET_HEIGHT - percentage * myController.SHEET_HEIGHT); + imageHeight = enlarge ? (int)(((float)myController.SHEET_NC_HEIGHT) * percentage): + (int)(myController.SHEET_NC_HEIGHT - percentage * myController.SHEET_HEIGHT); myWindow.repaint(); } @@ -133,9 +134,10 @@ public class SheetMessage { protected void paintCycleEnd() { setPositionRelativeToParent(); if (enlarge) { - imageHeight = myController.SHEET_HEIGHT; + imageHeight = myController.SHEET_NC_HEIGHT; staticImage = null; myWindow.setContentPane(myController.getPanel(myWindow)); + myController.requestFocus(); } else { if (restoreFullscreenButton) { @@ -152,8 +154,11 @@ public class SheetMessage { private void setPositionRelativeToParent () { int width = myParent.getWidth(); - myWindow.setLocation(width / 2 - myController.SHEET_WIDTH / 2 + myParent.getLocation().x, - myParent.getInsets().top + myParent.getLocation().y); + myWindow.setBounds(width / 2 - myController.SHEET_NC_WIDTH / 2 + myParent.getLocation().x, + myParent.getInsets().top + myParent.getLocation().y, + myController.SHEET_NC_WIDTH, + myController.SHEET_NC_HEIGHT); + } private void registerMoveResizeHandler () { diff --git a/platform/platform-impl/src/org/jetbrains/ide/BuiltInServerManagerImpl.java b/platform/platform-impl/src/org/jetbrains/ide/BuiltInServerManagerImpl.java index cf1104a405a2..51ebd5ef5c0c 100644 --- a/platform/platform-impl/src/org/jetbrains/ide/BuiltInServerManagerImpl.java +++ b/platform/platform-impl/src/org/jetbrains/ide/BuiltInServerManagerImpl.java @@ -20,6 +20,8 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.io.BuiltInServer; +import java.util.Random; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; @@ -39,11 +41,12 @@ public class BuiltInServerManagerImpl extends BuiltInServerManager { private BuiltInServer server; private boolean enabledInUnitTestMode = true; - //static { - // // IDEA-120811 - // System.setProperty("io.netty.machineId", Integer.toHexString(new Random().nextInt())); - // System.setProperty("io.netty.processId", "1"); - //} + static { + // IDEA-120811 + String id = UUID.randomUUID().toString(); + System.setProperty("io.netty.machineId", id.substring(id.length() - 8)); + System.setProperty("io.netty.processId", Integer.toString(new Random().nextInt(65535))); + } @Override public int getPort() { diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 8d51e6b5dbd2..79c6129ca776 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -107,8 +107,9 @@ action.EditorMoveUpAndScrollWithSelection.text=Move Up and Scroll with Selection action.EditorMoveDownAndScrollWithSelection.text=Move Down and Scroll with Selection action.EditorCloneCaretBelow.text=Clone Caret Below action.EditorCloneCaretAbove.text=Clone Caret Above -action.SelectNextOccurence.text=Select Next Occurence -action.UnselectLastOccurence.text=Unselect Last Occurence +action.SelectNextOccurrence.text=Select Next Occurrence +action.SelectAllOccurrences.text=Select All Occurrences +action.UnselectPreviousOccurrence.text=Unselect Occurrence action.EditorToggleStickySelection.text=Toggle Sticky Selection action.EditorSwapSelectionBoundaries.text=Swap selection boundaries action.EditorLineStart.text=Move Caret to Line Start @@ -910,7 +911,10 @@ action.XDebugger.JumpToSource.description=Open source of the selected item action.XDebugger.JumpToTypeSource.text=Jump To Type Source action.XDebugger.JumpToTypeSource.description=Open source of the selected value's type action.XDebugger.Inspect.text=Inspect... -action.XDebugger.AddToWatches.text=Add to Watches + +action.Debugger.Tree.AddToWatches.text=Add to Watches +action.Debugger.Tree.EvaluateInConsole.text=Evaluate In Console + action.XDebugger.RemoveWatch.text=Remove Watch action.XDebugger.RemoveAllWatches.text=Remove All Watches action.XDebugger.NewWatch.text=New Watch... @@ -949,6 +953,7 @@ action.Debugger.MarkObject.text=Mark Object... action.Debugger.MarkObject.unmark.text=Unmark Object action.Debugger.MarkObject.description=Mark/unmark the object so that it can be visually distinguished in in debugger views action.Debugger.AddToWatch.text=Add to Watches +action.Debugger.EvaluateInConsole.text=Evaluate in Console action.Debugger.AutoRenderer.text=Auto group.EditorPopupMenu.text=Editor Popup Menu group.EditorPopupMenu.description=Editor Popup Menu diff --git a/platform/platform-resources-en/src/messages/DiffBundle.properties b/platform/platform-resources-en/src/messages/DiffBundle.properties index 66a7bab05489..096fa117e2c8 100644 --- a/platform/platform-resources-en/src/messages/DiffBundle.properties +++ b/platform/platform-resources-en/src/messages/DiffBundle.properties @@ -32,7 +32,7 @@ diff.acton.ignore.whitespace.policy.do.not.ignore=Do not ignore diff.acton.ignore.whitespace.policy.leading.and.trailing=Leading and trailing diff.acton.ignore.whitespace.policy.all=All ignore.whitespace.acton.name=Ignore whitespace: -ignore.whitespace.action.not.available.action.name=<Not available> +diff.panel.combo.box.action.not.available.action.name=<Not available> diff.dialog.select.change.action.name=Select Change diff.dialog.select.change.action.description=Select changed text in this version and corresponding in other merge.files.dialog.title=Merge @@ -85,8 +85,7 @@ diff.content.selected.value=Selected Value diff.clipboard.vs.value.dialog.title=Clipboard vs Selected Value diff.can.not.show.unknown=Can not show diff for unknown file type -diff.acton.highlight.mode.action.by.word=By Word -diff.acton.highlight.mode.action.by.line=By Line -diff.acton.highlight.mode.action.no.highlighting=No Highlighting -diff.acton.highlight.mode.not.available.action.name=<Not available> -diff.acton.highlight.mode.action.name=Highlighting Mode: +diff.acton.highlight.mode.action.by.word=By word +diff.acton.highlight.mode.action.by.line=By line +diff.acton.highlight.mode.action.no.highlighting=Do not highlight +diff.acton.highlight.mode.action.name=Highlight: diff --git a/platform/platform-resources-en/src/messages/FindBundle.properties b/platform/platform-resources-en/src/messages/FindBundle.properties index 26959ba14d4b..2c17b13d459d 100644 --- a/platform/platform-resources-en/src/messages/FindBundle.properties +++ b/platform/platform-resources-en/src/messages/FindBundle.properties @@ -76,7 +76,7 @@ find.empty.match.regular.expression.error=Regular expression matches empty strin find.filter.invalid.file.mask.error=Bad file mask \"{0}\" find.filter.empty.file.mask.error=Empty file mask find.options.case.sensitive=&Case sensitive -find.options.replace.preserve.case=Preser&ve case +find.options.replace.preserve.case=&Preserve case find.options.whole.words.only=Whole wo&rds only (may be faster) find.options.string.literals.only=S&tring literals only find.options.comments.only=Comm&ents only @@ -85,7 +85,7 @@ find.direction.group=Direction find.direction.forward.radio=F&orward find.direction.backward.radio=&Backward find.scope.group=Scope -find.scope.whole.project.radio=Whole &project +find.scope.whole.project.radio=W&hole project find.scope.all.projects.radio=All &projects find.scope.module.radio=&Module: find.scope.project.radio=Pro&ject diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index b61965b67b3d..c1567482dc41 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -321,7 +321,6 @@ ui.no.bangs.and.whistles=false comment.by.line.bulk.lines.trigger=100 -scene.builder.start.executable=true junit_sm_runner=false testng_sm_runner=false show.flex.debug.design.view=false @@ -365,7 +364,7 @@ ide.open.file.in.temp.project.dir=true ide.open.file.in.temp.project.dir.description=Enables opening file in temp project directory editor.allow.multiple.carets=false -embed.scene.builder=false +embed.scene.builder=true dsm.retina.darcula.legend=true dsm.retina.darcula.legend.description=Experimental DSM legend component diff --git a/platform/platform-resources/src/DefaultColorSchemesManager.xml b/platform/platform-resources/src/DefaultColorSchemesManager.xml index d43993b72313..b3f6d7f21226 100644 --- a/platform/platform-resources/src/DefaultColorSchemesManager.xml +++ b/platform/platform-resources/src/DefaultColorSchemesManager.xml @@ -416,20 +416,6 @@ <option name="EFFECT_COLOR"/> </value> </option> - <option name="REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES"> - <value> - <option name="FOREGROUND"/> - <option name="BACKGROUND"/> - <option name="EFFECT_COLOR"/> - </value> - </option> - <option name="REASSIGNED_PARAMETER_ATTRIBUTES"> - <value> - <option name="FOREGROUND"/> - <option name="BACKGROUND"/> - <option name="EFFECT_COLOR"/> - </value> - </option> <option name="IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES"> <value> <option name="FOREGROUND" value="660e7a"/> diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index c554cf36ff7c..62fe04251a31 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -343,6 +343,9 @@ <projectService serviceInterface="com.intellij.openapi.roots.impl.LibraryScopeCache" serviceImplementation="com.intellij.openapi.roots.impl.LibraryScopeCache"/> + <projectService serviceInterface="com.intellij.ide.scratch.ScratchpadManager" + serviceImplementation="com.intellij.ide.scratch.ScratchpadManagerImpl"/> + <colorSettingsPage implementation="com.intellij.openapi.options.colors.pages.GeneralColorsPage" id="general"/> <colorSettingsPage implementation="com.intellij.openapi.options.colors.pages.DefaultLanguageColorsPage" id="defaultLanguage"/> <colorSettingsPage implementation="com.intellij.openapi.options.colors.pages.ANSIColoredConsoleColorsPage" id="ansi"/> @@ -875,6 +878,8 @@ <stepsBeforeRunProvider implementation="com.intellij.execution.impl.RunConfigurationBeforeRunProvider"/> <lang.foldingBuilder language="TEXT" implementationClass="com.intellij.ide.highlighter.custom.impl.CustomFileTypeFoldingBuilder"/> + + <virtualFileSystem key="scratchpad" implementationClass="com.intellij.ide.scratch.ScratchpadFileSystem"/> </extensions> </idea-plugin> diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 854e1ce08535..b6189cf69a47 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -190,6 +190,8 @@ <projectService serviceInterface="com.intellij.openapi.vcs.VcsFileListenerContextHelper" serviceImplementation="com.intellij.openapi.vcs.VcsFileListenerContextHelper"/> + <projectService serviceImplementation="com.intellij.openapi.editor.LazyRangeMarkerFactory"/> + <!-- General --> <applicationConfigurable instance="com.intellij.ide.GeneralSettingsConfigurable"/> diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index e34b74e756ab..a6d760367b5d 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -9,7 +9,8 @@ com.jetbrains.twig 133.51 130.1639 org.jetbrains.plugins.ruby 6.0.0.20140207 Pythonid 3.1 Karma 134.1163 134.1039 134.686 134.31 -org.intellij.scala 0.32.512 +org.intellij.scala 0.32.593 0.32.562 0.32.558 0.32.550 0.32.520 0.32.512 org.jetbrains.kannotator 0.2.420 SBT 1.0.0 1.1.0 1.2.0 1.3.0 1.3.1 1.4.0 1.5.0 -"JSTestDriver Plugin" 134.1163 134.686 134.31 134.307 134.1039
\ No newline at end of file +"JSTestDriver Plugin" 134.1163 134.686 134.31 134.307 134.1039 +AngularJS 134.1094 0.1.8 0.1.9
\ No newline at end of file diff --git a/platform/platform-resources/src/componentSets/Editor.xml b/platform/platform-resources/src/componentSets/Editor.xml index adf1f3bf5d7f..25719abb23f3 100644 --- a/platform/platform-resources/src/componentSets/Editor.xml +++ b/platform/platform-resources/src/componentSets/Editor.xml @@ -30,9 +30,5 @@ <interface-class>com.intellij.openapi.fileEditor.ex.IdeDocumentHistory</interface-class> <implementation-class>com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl</implementation-class> </component> - <component> - <implementation-class>com.intellij.openapi.editor.LazyRangeMarkerFactory</implementation-class> - <loadForDefaultProject/> - </component> </project-components> </components>
\ No newline at end of file diff --git a/platform/platform-resources/src/idea/Keymap_Default.xml b/platform/platform-resources/src/idea/Keymap_Default.xml index 447d4abfb649..c7135845bb32 100644 --- a/platform/platform-resources/src/idea/Keymap_Default.xml +++ b/platform/platform-resources/src/idea/Keymap_Default.xml @@ -115,7 +115,7 @@ <action id="SelectNextOccurrence"> <keyboard-shortcut first-keystroke="alt J"/> </action> - <action id="UnselectLastOccurrence"> + <action id="UnselectPreviousOccurrence"> <keyboard-shortcut first-keystroke="alt shift J"/> </action> <action id="GotoDeclaration"> @@ -958,5 +958,9 @@ <action id ="Refactorings.QuickListPopupAction"> <keyboard-shortcut first-keystroke="control alt shift T"/> </action> + + <action id="NewScratchFile"> + <keyboard-shortcut first-keystroke="control alt shift INSERT"/> + </action> </keymap> </component> diff --git a/platform/platform-resources/src/idea/Keymap_Eclipse.xml b/platform/platform-resources/src/idea/Keymap_Eclipse.xml index 2a28414bd583..ecc3b0488e6b 100644 --- a/platform/platform-resources/src/idea/Keymap_Eclipse.xml +++ b/platform/platform-resources/src/idea/Keymap_Eclipse.xml @@ -121,10 +121,13 @@ <action id="FindPrevious"> <keyboard-shortcut first-keystroke="shift control K" /> </action> + <action id="SelectAllOccurrences"> + <keyboard-shortcut first-keystroke="alt control Y"/> + </action> <action id="SelectNextOccurrence"> <keyboard-shortcut first-keystroke="alt Y"/> </action> - <action id="UnselectLastOccurrence"> + <action id="UnselectPreviousOccurrence"> <keyboard-shortcut first-keystroke="alt shift Y"/> </action> <action id="FindUsages"> diff --git a/platform/platform-resources/src/idea/Keymap_Mac.xml b/platform/platform-resources/src/idea/Keymap_Mac.xml index 42cf466cd85b..32dd27f12dfe 100644 --- a/platform/platform-resources/src/idea/Keymap_Mac.xml +++ b/platform/platform-resources/src/idea/Keymap_Mac.xml @@ -349,6 +349,16 @@ <action id="FindPrevious"> <keyboard-shortcut first-keystroke="meta shift G"/> </action> + + <action id="SelectNextOccurrence"> + <keyboard-shortcut first-keystroke="control G"/> + </action> + <action id="UnselectPreviousOccurrence"> + <keyboard-shortcut first-keystroke="control shift G"/> + </action> + <action id="SelectAllOccurrences"> + <keyboard-shortcut first-keystroke="meta control G"/> + </action> <action id="Run"> <keyboard-shortcut first-keystroke="control R"/> @@ -538,5 +548,9 @@ <action id ="Refactorings.QuickListPopupAction"> <keyboard-shortcut first-keystroke="control T"/> </action> + + <action id="NewScratchFile"> + <keyboard-shortcut first-keystroke="meta shift N"/> + </action> </keymap> </component> diff --git a/platform/platform-resources/src/idea/Keymap_MacClassic.xml b/platform/platform-resources/src/idea/Keymap_MacClassic.xml index 1ce8e72fa7bc..532ac8983908 100644 --- a/platform/platform-resources/src/idea/Keymap_MacClassic.xml +++ b/platform/platform-resources/src/idea/Keymap_MacClassic.xml @@ -258,6 +258,16 @@ <keyboard-shortcut first-keystroke="shift F3"/> <keyboard-shortcut first-keystroke="control shift L"/> </action> + + <action id="SelectNextOccurrence"> + <keyboard-shortcut first-keystroke="control G"/> + </action> + <action id="UnselectPreviousOccurrence"> + <keyboard-shortcut first-keystroke="control shift G"/> + </action> + <action id="SelectAllOccurrences"> + <keyboard-shortcut first-keystroke="meta control G"/> + </action> <action id="VcsShowNextChangeMarker"> <keyboard-shortcut first-keystroke="shift control alt DOWN"/> diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index bdaf6c857512..3b8798230323 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -319,6 +319,10 @@ <add-to-group group-id="ToolsMenu" anchor="last"/> </group> + <action id="NewScratchFile" class="com.intellij.ide.scratch.CreateScratchFileAction"> + <add-to-group group-id="ToolsBasicGroup" anchor="first"/> + </action> + <group id="NewGroup" popup="true"> <action id="NewFile" class="com.intellij.ide.actions.CreateFileAction"/> <action id="NewDir" class="com.intellij.ide.actions.CreateDirectoryOrPackageAction"/> @@ -641,6 +645,7 @@ </group> <action id="Debugger.AddToWatch" class="com.intellij.xdebugger.impl.actions.AddToWatchesAction" icon="AllIcons.Debugger.AddToWatch"/> + <action id="Debugger.EvaluateInConsole" class="com.intellij.xdebugger.impl.actions.EvaluateInConsoleAction"/> <group id="EditorPopupMenuDebug"> <separator/> @@ -648,6 +653,7 @@ <reference ref="RunToCursor"/> <reference ref="ForceRunToCursor"/> <reference ref="Debugger.AddToWatch"/> + <reference ref="Debugger.EvaluateInConsole"/> <separator/> <add-to-group group-id="EditorLangPopupMenu" relative-to-action="EditorPopupMenu.Run" anchor="before"/> @@ -662,7 +668,10 @@ <action id="XDebugger.Inspect" class="com.intellij.xdebugger.impl.ui.tree.actions.XInspectAction"/> <action id="XDebugger.JumpToSource" class="com.intellij.xdebugger.impl.ui.tree.actions.XJumpToSourceAction"/> <action id="XDebugger.JumpToTypeSource" class="com.intellij.xdebugger.impl.ui.tree.actions.XJumpToTypeSourceAction"/> - <action id="XDebugger.AddToWatches" class="com.intellij.xdebugger.impl.ui.tree.actions.XAddToWatchesAction" icon="AllIcons.Debugger.AddToWatch"/> + + <action id="Debugger.Tree.AddToWatches" class="com.intellij.xdebugger.impl.ui.tree.actions.XAddToWatchesAction" icon="AllIcons.Debugger.AddToWatch"/> + <action id="Debugger.Tree.EvaluateInConsole" class="com.intellij.xdebugger.impl.ui.tree.actions.EvaluateInConsoleFromTreeAction"/> + <action id="XDebugger.NewWatch" class="com.intellij.xdebugger.impl.frame.actions.XNewWatchAction" icon="AllIcons.Debugger.NewWatch"/> <action id="XDebugger.EditWatch" class="com.intellij.xdebugger.impl.frame.actions.XEditWatchAction"/> <action id="XDebugger.RemoveWatch" class="com.intellij.xdebugger.impl.frame.actions.XRemoveWatchAction" icon="AllIcons.Actions.Delete"/> @@ -712,7 +721,8 @@ <reference ref="XDebugger.ValueGroup"/> <reference ref="XDebugger.JumpToSource"/> <reference ref="XDebugger.JumpToTypeSource"/> - <reference ref="XDebugger.AddToWatches"/> + <reference ref="Debugger.Tree.AddToWatches"/> + <reference ref="Debugger.Tree.EvaluateInConsole"/> </group> <group id="XDebugger.Variables.Tree.Toolbar"> @@ -733,7 +743,8 @@ <group id="XDebugger.Inspect.Tree.Popup"> <reference ref="XDebugger.ValueGroup"/> - <reference ref="XDebugger.AddToWatches"/> + <reference ref="Debugger.Tree.AddToWatches"/> + <reference ref="Debugger.Tree.EvaluateInConsole"/> </group> <group id="XDebugger.Settings" icon="AllIcons.General.SecondaryGroup" popup="true"> diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index e0e136024f2a..5d2d399712d7 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -225,8 +225,9 @@ <action id="FindNext" class="com.intellij.ide.actions.SearchAgainAction"/> <action id="FindPrevious" class="com.intellij.ide.actions.SearchBackAction"/> <action id="FindWordAtCaret" class="com.intellij.openapi.editor.actions.FindWordAtCaretAction"/> + <action id="SelectAllOccurrences" class="com.intellij.openapi.editor.actions.SelectAllOccurrencesAction"/> <action id="SelectNextOccurrence" class="com.intellij.openapi.editor.actions.SelectNextOccurrenceAction"/> - <action id="UnselectLastOccurrence" class="com.intellij.openapi.editor.actions.UnselectLastOccurrenceAction"/> + <action id="UnselectPreviousOccurrence" class="com.intellij.openapi.editor.actions.UnselectPreviousOccurrenceAction"/> <separator/> <action id="FindInPath" class="com.intellij.find.actions.FindInPathAction"/> <action id="ReplaceInPath" class="com.intellij.find.actions.ReplaceInPathAction"/> diff --git a/platform/platform-tests/platform-tests.iml b/platform/platform-tests/platform-tests.iml index d1018688da69..f6d37e431c5e 100644 --- a/platform/platform-tests/platform-tests.iml +++ b/platform/platform-tests/platform-tests.iml @@ -23,6 +23,7 @@ <orderEntry type="library" name="Groovy" level="project" /> <orderEntry type="library" name="Netty" level="project" /> <orderEntry type="library" name="http-client" level="project" /> + <orderEntry type="module" module-name="jps-model-impl" scope="TEST" /> </component> </module> diff --git a/platform/platform-tests/testSrc/com/intellij/history/integration/TestVirtualFile.java b/platform/platform-tests/testSrc/com/intellij/history/integration/TestVirtualFile.java index 990291816e30..44473dfdfe64 100644 --- a/platform/platform-tests/testSrc/com/intellij/history/integration/TestVirtualFile.java +++ b/platform/platform-tests/testSrc/com/intellij/history/integration/TestVirtualFile.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,12 +33,12 @@ import java.util.List; // todo get rid of!!!!!!!!!!!!! public class TestVirtualFile extends VirtualFile { - private String myName; + private final String myName; private String myContent; private boolean isReadOnly; private long myTimestamp; - private boolean IsDirectory; + private final boolean IsDirectory; private VirtualFile myParent; private final List<TestVirtualFile> myChildren = new ArrayList<TestVirtualFile>(); @@ -76,6 +76,7 @@ public class TestVirtualFile extends VirtualFile { return IsDirectory; } + @NotNull @Override public String getPath() { if (myParent == null) return myName; diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/IgnoreWhiteSpaceTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/IgnoreWhiteSpaceTest.java index 7eb6c45e6b4f..de5a6ba61b2b 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/IgnoreWhiteSpaceTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/IgnoreWhiteSpaceTest.java @@ -31,4 +31,13 @@ public class IgnoreWhiteSpaceTest extends TestCase { assertEquals(keys[1], keys[2]); assertFalse(keys[2].equals(keys[3])); } + + public static void assertEquals(Object obj1, Object obj2) { + if (obj1 instanceof CharSequence && obj2 instanceof CharSequence) { + assertEquals(obj1.toString(), obj2.toString()); + return; + } + + assertEquals(obj1, obj2); + } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/highlighting/UtilTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/highlighting/UtilTest.java index db929203a68a..1d19fb92ee44 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/highlighting/UtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/highlighting/UtilTest.java @@ -2,6 +2,7 @@ package com.intellij.openapi.diff.impl.highlighting; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.MultiCheck; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.util.Assertion; import com.intellij.util.diff.Diff; import com.intellij.util.diff.FilesTooBigForDiffException; @@ -209,10 +210,11 @@ public class UtilTest extends TestCase { last}; lines = Util.uniteFormattingOnly(lines); CHECK.compareAll(new DiffFragment[][]{ - first, - new DiffFragment[]{inline1, inline2, inline3, inline4}, - last}, - lines); + first, + new DiffFragment[]{inline1, inline2, inline3, inline4}, + last}, + lines + ); } public void testConcatenateEquals() { @@ -246,7 +248,8 @@ public class UtilTest extends TestCase { CHECK.singleElement(Util.cutFirst(new DiffFragment[]{ DiffFragment.unchanged("ab", "ac") }), - DiffFragment.unchanged("b", "c")); + DiffFragment.unchanged("b", "c") + ); CHECK.compareAll(new DiffFragment[]{ new DiffFragment(null, "c") @@ -264,7 +267,8 @@ public class UtilTest extends TestCase { Util.cutFirst(new DiffFragment[]{ new DiffFragment(null, "ab"), new DiffFragment("c", "d") - })); + }) + ); } public void testCutFirst2() { @@ -293,4 +297,8 @@ public class UtilTest extends TestCase { })); } + + public static void assertEquals(CharSequence obj1, CharSequence obj2) { + assertEquals(obj1.toString(), obj2.toString()); + } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/processing/LineBlocksDiffPolicyTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/processing/LineBlocksDiffPolicyTest.java index badcc338a445..2baf119ba240 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/processing/LineBlocksDiffPolicyTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/processing/LineBlocksDiffPolicyTest.java @@ -5,7 +5,6 @@ import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.Util; import com.intellij.util.diff.FilesTooBigForDiffException; -import junit.framework.Assert; import junit.framework.TestCase; public class LineBlocksDiffPolicyTest extends TestCase{ @@ -16,9 +15,9 @@ public class LineBlocksDiffPolicyTest extends TestCase{ checkPolicy(diffPolicy, "abc\n123\n", "ABC\nXYZ"); } - private void checkPolicy(DiffPolicy.LineBlocks diffPolicy, String text1, String text2) throws FilesTooBigForDiffException { + private static void checkPolicy(DiffPolicy.LineBlocks diffPolicy, String text1, String text2) throws FilesTooBigForDiffException { DiffFragment[] fragments = diffPolicy.buildFragments(text1, text2); - Assert.assertEquals(text1, Util.getText(fragments, FragmentSide.SIDE1)); - assertEquals(text2, Util.getText(fragments, FragmentSide.SIDE2)); + assertEquals(text1, Util.getText(fragments, FragmentSide.SIDE1).toString()); + assertEquals(text2, Util.getText(fragments, FragmentSide.SIDE2).toString()); } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/processing/TextCompareProcessorTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/processing/TextCompareProcessorTest.java index 4d4ed9b9937f..854a17d47ebd 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/processing/TextCompareProcessorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/processing/TextCompareProcessorTest.java @@ -5,12 +5,12 @@ import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.util.diff.FilesTooBigForDiffException; import junit.framework.TestCase; -import java.util.ArrayList; +import java.util.List; public class TextCompareProcessorTest extends TestCase { public void testIgnoreWrappingEqualText() throws FilesTooBigForDiffException { TextCompareProcessor processor = new TextCompareProcessor(ComparisonPolicy.IGNORE_SPACE); - ArrayList<LineFragment> lineFragments = processor.process("f(a, b)\n", "f(a,\nb)\n"); + List<LineFragment> lineFragments = processor.process("f(a, b)\n", "f(a,\nb)\n"); assertTrue(lineFragments.size() == 1); assertNull(lineFragments.get(0).getType()); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretColumnModeTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretColumnModeTest.java index 9b94c44ab059..c4433cd15ca9 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretColumnModeTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretColumnModeTest.java @@ -16,12 +16,12 @@ package com.intellij.openapi.editor; import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.impl.AbstractEditorTest; import com.intellij.testFramework.EditorTestUtil; -import com.intellij.testFramework.LightPlatformCodeInsightTestCase; import java.io.IOException; -public class EditorMultiCaretColumnModeTest extends LightPlatformCodeInsightTestCase { +public class EditorMultiCaretColumnModeTest extends AbstractEditorTest { public void setUp() throws Exception { super.setUp(); EditorTestUtil.enableMultipleCarets(); @@ -192,8 +192,99 @@ public class EditorMultiCaretColumnModeTest extends LightPlatformCodeInsightTest "bbbb bb<selection>bb<caret></selection>"); } + public void testMoveToSelectionStart() throws Exception { + init("a"); + mouse().clickAt(0, 2).dragTo(0, 4).release(); + verifyCaretsAndSelections(0, 4, 0, 2, 0, 4); + + executeAction("EditorLeft"); + verifyCaretsAndSelections(0, 2, 0, 2, 0, 2); + } + + public void testMoveToSelectionEnd() throws Exception { + init("a"); + mouse().clickAt(0, 4).dragTo(0, 2).release(); + verifyCaretsAndSelections(0, 2, 0, 2, 0, 4); + + executeAction("EditorRight"); + verifyCaretsAndSelections(0, 4, 0, 4, 0, 4); + } + + public void testReverseBlockSelection() throws Exception { + init("a"); + mouse().clickAt(0, 4).dragTo(0, 3).release(); + verifyCaretsAndSelections(0, 3, 0, 3, 0, 4); + + executeAction("EditorRightWithSelection"); + verifyCaretsAndSelections(0, 4, 0, 4, 0, 4); + } + + public void testSelectionWithKeyboardInEmptySpace() throws Exception { + init("\n\n"); + mouse().clickAt(1, 1); + verifyCaretsAndSelections(1, 1, 1, 1, 1, 1); + + executeAction("EditorRightWithSelection"); + verifyCaretsAndSelections(1, 2, 1, 1, 1, 2); + + executeAction("EditorDownWithSelection"); + verifyCaretsAndSelections(1, 2, 1, 1, 1, 2, + 2, 2, 2, 1, 2, 2); + + executeAction("EditorLeftWithSelection"); + verifyCaretsAndSelections(1, 1, 1, 1, 1, 1, + 2, 1, 2, 1, 2, 1); + + executeAction("EditorLeftWithSelection"); + verifyCaretsAndSelections(1, 0, 1, 0, 1, 1, + 2, 0, 2, 0, 2, 1); + + executeAction("EditorUpWithSelection"); + verifyCaretsAndSelections(1, 0, 1, 0, 1, 1); + + executeAction("EditorUpWithSelection"); + verifyCaretsAndSelections(0, 0, 0, 0, 0, 1, + 1, 0, 1, 0, 1, 1); + + executeAction("EditorRightWithSelection"); + verifyCaretsAndSelections(0, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 1); + + executeAction("EditorRightWithSelection"); + verifyCaretsAndSelections(0, 2, 0, 1, 0, 2, + 1, 2, 1, 1, 1, 2); + + executeAction("EditorDownWithSelection"); + verifyCaretsAndSelections(1, 2, 1, 1, 1, 2); + + executeAction("EditorLeftWithSelection"); + verifyCaretsAndSelections(1, 1, 1, 1, 1, 1); + } + + public void testBlockSelection() throws Exception { + init("a\n" + + "bbb\n" + + "ccccc"); + mouse().clickAt(2, 4).dragTo(0, 1).release(); + verifyCaretsAndSelections(0, 1, 0, 1, 0, 4, + 1, 1, 1, 1, 1, 4, + 2, 1, 2, 1, 2, 4); + } + + public void testTyping() throws Exception { + init("a\n" + + "bbb\n" + + "ccccc"); + mouse().clickAt(0, 2).dragTo(2, 3).release(); + type('S'); + checkResultByText("a S<caret>\n" + + "bbS<caret>\n" + + "ccS<caret>cc"); + } + private void init(String text) throws IOException { configureFromFileText(getTestName(false) + ".txt", text); + EditorTestUtil.setEditorVisibleSize(myEditor, 1000, 1000); ((EditorEx)myEditor).setColumnMode(true); } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretUndoRedoTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretUndoRedoTest.java index 0b168c4cf813..6f13af47dee5 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretUndoRedoTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretUndoRedoTest.java @@ -21,6 +21,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.impl.CurrentEditorProvider; import com.intellij.openapi.command.impl.UndoManagerImpl; import com.intellij.openapi.command.undo.UndoManager; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.impl.AbstractEditorTest; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.TextEditor; @@ -29,6 +30,8 @@ import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.TestFileType; import org.jetbrains.annotations.NotNull; +import java.io.IOException; + public class EditorMultiCaretUndoRedoTest extends AbstractEditorTest { private CurrentEditorProvider mySavedCurrentEditorProvider; @@ -58,9 +61,7 @@ public class EditorMultiCaretUndoRedoTest extends AbstractEditorTest { public void testUndoRedo() throws Exception { init("some<caret> text<caret>\n" + "some <selection><caret>other</selection> <selection>text<caret></selection>\n" + - "<selection>ano<caret>ther</selection> line", - TestFileType.TEXT); - setupEditorProvider(); + "<selection>ano<caret>ther</selection> line"); type('A'); executeAction("EditorDelete"); mouse().clickAt(0, 1); @@ -80,6 +81,25 @@ public class EditorMultiCaretUndoRedoTest extends AbstractEditorTest { "A<caret> line"); } + public void testBlockSelectionStateAfterUndo() throws Exception { + init("a"); + ((EditorEx)myEditor).setColumnMode(true); + mouse().clickAt(0, 2); + type('b'); + undo(); + executeAction("EditorRightWithSelection"); + verifyCaretsAndSelections(0, 3, 0, 2, 0, 3); + } + + public void testBlockSelectionStateAfterUndo2() throws Exception { + init("a"); + ((EditorEx)myEditor).setColumnMode(true); + mouse().clickAt(0, 0).dragTo(0, 2).release(); + type('b'); + undo(); + verifyCaretsAndSelections(0, 2, 0, 0, 0, 2); + } + private void checkResult(final String text) { CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { @Override @@ -105,7 +125,9 @@ public class EditorMultiCaretUndoRedoTest extends AbstractEditorTest { return TextEditorProvider.getInstance().getTextEditor(myEditor); } - private static void setupEditorProvider() { + private void init(String text) throws IOException { + init(text, TestFileType.TEXT); + EditorTestUtil.setEditorVisibleSize(myEditor, 1000, 1000); getUndoManager().setEditorProvider(new CurrentEditorProvider() { @Override public FileEditor getCurrentEditor() { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/SelectUnselectOccurrenceActionsTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/SelectUnselectOccurrenceActionsTest.java index 90a82e972379..42faeaa86e85 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/SelectUnselectOccurrenceActionsTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/SelectUnselectOccurrenceActionsTest.java @@ -49,6 +49,30 @@ public class SelectUnselectOccurrenceActionsTest extends LightPlatformCodeInsigh super.tearDown(); } + public void testAllWithoutInitialSelection() throws Exception { + init("some t<caret>ext\n" + + "some texts\n" + + "another text here" + ); + executeSelectAllAction(); + checkResult("some <selection>t<caret>ext</selection>\n" + + "some texts\n" + + "another <selection>t<caret>ext</selection> here"); + } + + public void testAllWithInitialWholeWordSelection() throws Exception { + init("some <selection>t<caret>ext</selection>\n" + + "some texts\n" + + "some texts\n" + + "another text here"); + executeSelectAllAction(); + checkResult("some <selection>t<caret>ext</selection>\n" + + "some texts\n" + + "some texts\n" + + "another <selection>t<caret>ext</selection> here"); + assertEquals(0, hintCount); + } + public void testNoInitialSelection() throws Exception { init("some t<caret>ext\n" + "some texts\n" + @@ -182,6 +206,10 @@ public class SelectUnselectOccurrenceActionsTest extends LightPlatformCodeInsigh } private void executeReverseAction() { - myFixture.performEditorAction(IdeActions.ACTION_UNSELECT_LAST_OCCURENCE); + myFixture.performEditorAction(IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE); + } + + private void executeSelectAllAction() { + myFixture.performEditorAction(IdeActions.ACTION_SELECT_ALL_OCCURRENCES); } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/AbstractEditorTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/AbstractEditorTest.java index bbb8de3200cc..2c460a5ad6b0 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/AbstractEditorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/AbstractEditorTest.java @@ -15,9 +15,7 @@ */ package com.intellij.openapi.editor.impl; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.FoldRegion; -import com.intellij.openapi.editor.FoldingModel; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.ex.FoldingModelEx; import com.intellij.openapi.editor.impl.softwrap.mapping.CachingSoftWrapDataMapper; import com.intellij.openapi.util.Pair; @@ -220,4 +218,18 @@ public abstract class AbstractEditorTest extends LightPlatformCodeInsightTestCas public EditorMouseFixture mouse() { return new EditorMouseFixture((EditorImpl)myEditor); } + + // for each caret its visual position and visual positions of selection start an and should be provided in the following order: + // caretLine, caretColumn, selectionStartLine, selectionStartColumn, selectionEndLine, selectionEndColumn + public static void verifyCaretsAndSelections(int... coordinates) { + int caretCount = coordinates.length / 6; + List<Caret> carets = myEditor.getCaretModel().getAllCarets(); + assertEquals("Unexpected caret count", caretCount, carets.size()); + for (int i = 0; i < caretCount; i++) { + Caret caret = carets.get(i); + assertEquals("Unexpected position for caret " + (i + 1), new VisualPosition(coordinates[i * 6], coordinates[i * 6 + 1]), caret.getVisualPosition()); + assertEquals("Unexpected selection start for caret " + (i + 1), new VisualPosition(coordinates[i * 6 + 2], coordinates[i * 6 + 3]), caret.getSelectionStartPosition()); + assertEquals("Unexpected selection end for caret " + (i + 1), new VisualPosition(coordinates[i * 6 + 4], coordinates[i * 6 + 5]), caret.getSelectionEndPosition()); + } + } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/IterationStateTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/IterationStateTest.java index 2b8f99e2693a..2502e767b331 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/IterationStateTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/IterationStateTest.java @@ -15,21 +15,42 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.testFramework.EditorTestUtil; +import com.intellij.testFramework.fixtures.EditorMouseFixture; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; -import org.jetbrains.annotations.NotNull; import org.junit.Assert; import java.awt.*; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase { + private Color DEFAULT_BACKGROUND; + private Color CARET_ROW_BACKGROUND; + private Color SELECTION_BACKGROUND; + + @Override + public void setUp() throws Exception { + super.setUp(); + EditorColorsScheme colorsScheme = EditorColorsManager.getInstance().getGlobalScheme(); + DEFAULT_BACKGROUND = colorsScheme.getDefaultBackground(); + CARET_ROW_BACKGROUND = colorsScheme.getColor(EditorColors.CARET_ROW_COLOR); + SELECTION_BACKGROUND = colorsScheme.getColor(EditorColors.SELECTION_BACKGROUND_COLOR); + assertEquals(3, new HashSet<Color>(Arrays.asList(DEFAULT_BACKGROUND, CARET_ROW_BACKGROUND, SELECTION_BACKGROUND)).size()); + } + public void testBlockSelection() { - verifySplitting("aa,<block>bb\ncc,d</block>d", + init("aa,<block>bb\n" + + "cc,d</block>d"); + verifySplitting(true, new Segment(0, 3, Color.BLACK), new Segment(3, 4, Color.WHITE), new Segment(4, 5, Color.BLACK), @@ -49,20 +70,106 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase } } - private void verifySplitting(String text, Segment... expectedSegments) { - myFixture.configureByText(PlainTextFileType.INSTANCE, text); + public void testColumnModeBlockSelection() { + EditorTestUtil.enableMultipleCarets(); + try { + init("a\n" + + "bbb\n" + + "ccccc"); + setColumnModeOn(); + mouse().clickAt(0, 2).dragTo(2, 4).release(); + verifySplitting(false, + new Segment(0, 1, DEFAULT_BACKGROUND), + new Segment(1, 2, DEFAULT_BACKGROUND).plus(1, DEFAULT_BACKGROUND).plus(2, SELECTION_BACKGROUND), + new Segment(2, 4, DEFAULT_BACKGROUND), + new Segment(4, 5, SELECTION_BACKGROUND), + new Segment(5, 6, DEFAULT_BACKGROUND).plus(1, SELECTION_BACKGROUND), + new Segment(6, 8, CARET_ROW_BACKGROUND), + new Segment(8, 10, SELECTION_BACKGROUND), + new Segment(10, 11, CARET_ROW_BACKGROUND)); + } + finally { + EditorTestUtil.disableMultipleCarets(); + } + } + + public void testColumnModeBlockSelectionAtLastNonEmptyLine() { + EditorTestUtil.enableMultipleCarets(); + try { + init("a\n" + + "bbb\n" + + "ccccc"); + setColumnModeOn(); + mouse().clickAt(0, 2).dragTo(2, 6).release(); + verifySplitting(false, + new Segment(0, 1, DEFAULT_BACKGROUND), + new Segment(1, 2, DEFAULT_BACKGROUND).plus(1, DEFAULT_BACKGROUND).plus(4, SELECTION_BACKGROUND), + new Segment(2, 4, DEFAULT_BACKGROUND), + new Segment(4, 5, SELECTION_BACKGROUND), + new Segment(5, 6, DEFAULT_BACKGROUND).plus(3, SELECTION_BACKGROUND), + new Segment(6, 8, CARET_ROW_BACKGROUND), + new Segment(8, 11, SELECTION_BACKGROUND), + new Segment(11, 11, null).plus(1, SELECTION_BACKGROUND)); + } + finally { + EditorTestUtil.disableMultipleCarets(); + } + } + + public void testColumnModeBlockSelectionAtLastEmptyLine() { + EditorTestUtil.enableMultipleCarets(); + try { + init("a\n" + + ""); + setColumnModeOn(); + mouse().clickAt(1, 1).dragTo(1, 2).release(); + verifySplitting(false, + new Segment(0, 1, DEFAULT_BACKGROUND), + new Segment(1, 2, DEFAULT_BACKGROUND), + new Segment(2, 2, null).plus(1, CARET_ROW_BACKGROUND).plus(1, SELECTION_BACKGROUND)); + } + finally { + EditorTestUtil.disableMultipleCarets(); + } + } + + public void testColumnModeBlockSelectionAtEmptyLines() { + EditorTestUtil.enableMultipleCarets(); + try { + init("\n"); + setColumnModeOn(); + mouse().clickAt(0, 1).dragTo(1, 2).release(); + verifySplitting(false, + new Segment(0, 1, DEFAULT_BACKGROUND).plus(1, DEFAULT_BACKGROUND).plus(1, SELECTION_BACKGROUND), + new Segment(1, 1, null).plus(1, CARET_ROW_BACKGROUND).plus(1, SELECTION_BACKGROUND)); + } + finally { + EditorTestUtil.disableMultipleCarets(); + } + } + + private void verifySplitting(boolean checkForegroundColor, Segment... expectedSegments) { EditorEx editor = (EditorEx)myFixture.getEditor(); IterationState iterationState = new IterationState(editor, 0, editor.getDocument().getTextLength(), true); try { List<Segment> actualSegments = new ArrayList<Segment>(); do { - actualSegments.add(new Segment(iterationState.getStartOffset(), - iterationState.getEndOffset(), - iterationState.getMergedAttributes().getForegroundColor())); + Segment segment = new Segment(iterationState.getStartOffset(), + iterationState.getEndOffset(), + checkForegroundColor ? iterationState.getMergedAttributes().getForegroundColor() + : iterationState.getMergedAttributes().getBackgroundColor()); + readPastLineState(iterationState, segment); + actualSegments.add(segment); iterationState.advance(); } while (!iterationState.atEnd()); + if (iterationState.hasPastFileEndBackgroundSegments()) { + Segment segment = new Segment(iterationState.getEndOffset(), iterationState.getEndOffset(), null); + readPastLineState(iterationState, segment); + actualSegments.add(segment); + } + Assert.assertArrayEquals(expectedSegments, actualSegments.toArray()); } finally { @@ -70,15 +177,46 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase } } + private static void readPastLineState(IterationState iterationState, Segment segment) { + while(iterationState.hasPastLineEndBackgroundSegment()) { + segment.plus(iterationState.getPastLineEndBackgroundSegmentWidth(), iterationState.getPastLineEndBackgroundAttributes().getBackgroundColor()); + iterationState.advanceToNextPastLineEndBackgroundSegment(); + } + } + + private void init(String text) { + myFixture.configureByText(PlainTextFileType.INSTANCE, text); + EditorTestUtil.setEditorVisibleSize(myFixture.getEditor(), 1000, 1000); + } + + private void setColumnModeOn() { + ((EditorEx)myFixture.getEditor()).setColumnMode(true); + } + + private EditorMouseFixture mouse() { + return new EditorMouseFixture((EditorImpl)myFixture.getEditor()); + } + private static class Segment { private final int start; private final int end; - private final Color fgColor; + private final Color color; + private final List<Integer> pastLineEndSegmentWidths = new ArrayList<Integer>(); + private final List<Color> pastLineEndSegmentColors = new ArrayList<Color>(); - private Segment(int start, int end, @NotNull Color fgColor) { + private Segment(int start, int end, Color color) { this.start = start; this.end = end; - this.fgColor = fgColor; + this.color = color; + } + + /** + * Adds a past-line-end background segment + */ + private Segment plus(int width, Color color) { + pastLineEndSegmentWidths.add(width); + pastLineEndSegmentColors.add(color); + return this; } @Override @@ -90,7 +228,9 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase if (end != segment.end) return false; if (start != segment.start) return false; - if (!fgColor.equals(segment.fgColor)) return false; + if (color != null ? !color.equals(segment.color) : segment.color != null) return false; + if (!pastLineEndSegmentColors.equals(segment.pastLineEndSegmentColors)) return false; + if (!pastLineEndSegmentWidths.equals(segment.pastLineEndSegmentWidths)) return false; return true; } @@ -99,7 +239,9 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase public int hashCode() { int result = start; result = 31 * result + end; - result = 31 * result + fgColor.hashCode(); + result = 31 * result + (color != null ? color.hashCode() : 0); + result = 31 * result + pastLineEndSegmentWidths.hashCode(); + result = 31 * result + pastLineEndSegmentColors.hashCode(); return result; } @@ -108,7 +250,9 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase return "Segment{" + "start=" + start + ", end=" + end + - ", color=" + fgColor + + ", color=" + color + + (pastLineEndSegmentWidths.isEmpty() ? "" : ", pastLineEndSegmentWidths=" + pastLineEndSegmentWidths) + + (pastLineEndSegmentColors.isEmpty() ? "" : ", pastLineEndSegmentColors=" + pastLineEndSegmentColors) + '}'; } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileEditorManagerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileEditorManagerTest.java index cf53f977c813..09debec55b6b 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileEditorManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileEditorManagerTest.java @@ -17,29 +17,20 @@ package com.intellij.openapi.fileEditor; import com.intellij.ide.ui.UISettings; import com.intellij.mock.Mock; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.ExpandMacroToPathMap; import com.intellij.openapi.fileEditor.impl.EditorWithProviderComposite; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; -import org.jdom.Document; import org.jdom.Element; -import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jps.model.serialization.PathMacroUtil; import javax.swing.*; import java.io.File; -import java.io.IOException; import java.util.Arrays; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; /** * @author Dmitry Avdeev @@ -77,17 +68,18 @@ public class FileEditorManagerTest extends FileEditorManagerTestCase { openFiles(" <component name=\"FileEditorManager\">\n" + " <leaf>\n" + - " <file leaf-file-name=\"foo.xsd\" pinned=\"false\" current=\"true\" current-in-tab=\"true\">\n" + - " <entry selected=\"true\" file=\"file://$PROJECT_DIR$/src/1.txt\">\n" + - " <provider editor-type-id=\"mock\" selected=\"true\">\n" + - " <state />\n" + - " </provider>\n" + - " <provider editor-type-id=\"text-editor\">\n" + - " <state/>\n" + + " <file leaf-file-name=\"Bar.java\" pinned=\"false\" current=\"false\" current-in-tab=\"false\">\n" + + " <entry file=\"file://$PROJECT_DIR$/src/Bar.java\">\n" + + " <provider selected=\"true\" editor-type-id=\"text-editor\">\n" + + " <state vertical-scroll-proportion=\"0.0\" vertical-offset=\"0\" max-vertical-offset=\"187\">\n" + + " <caret line=\"1\" column=\"26\" selection-start=\"45\" selection-end=\"45\" />\n" + + " <folding>\n" + + " <element signature=\"e#69#70#0\" expanded=\"true\" />\n" + + " </folding>\n" + + " </state>\n" + " </provider>\n" + " </entry>\n" + " </file>\n" + - " </leaf>\n" + " </component>\n"); FileEditor[] selectedEditors = myManager.getSelectedEditors(); assertEquals(1, selectedEditors.length); @@ -157,24 +149,6 @@ public class FileEditorManagerTest extends FileEditorManagerTestCase { assertEquals(Arrays.asList(fileNames), names); } - private void openFiles(String s) throws IOException, JDOMException, InterruptedException, ExecutionException { - Document document = JDOMUtil.loadDocument(s); - Element rootElement = document.getRootElement(); - ExpandMacroToPathMap map = new ExpandMacroToPathMap(); - map.addMacroExpand(PathMacroUtil.PROJECT_DIR_MACRO_NAME, getTestDataPath()); - map.substitute(rootElement, true, true); - - myManager.readExternal(rootElement); - - Future<?> future = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - myManager.getMainSplitters().openFiles(); - } - }); - future.get(); - } - @Override protected String getTestDataPath() { return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + "/platform/platform-tests/testData/fileEditorManager"; diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileEditorManagerTestCase.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileEditorManagerTestCase.java index aa528681114b..28d5def0a218 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileEditorManagerTestCase.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileEditorManagerTestCase.java @@ -1,13 +1,27 @@ package com.intellij.openapi.fileEditor; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.ExpandMacroToPathMap; import com.intellij.openapi.components.impl.ComponentManagerImpl; import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager; import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl; import com.intellij.openapi.fileEditor.impl.FileEditorProviderManagerImpl; +import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; import com.intellij.ui.docking.DockManager; +import com.intellij.util.ui.UIUtil; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jetbrains.jps.model.serialization.PathMacroUtil; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * @author Dmitry Avdeev @@ -40,4 +54,30 @@ public abstract class FileEditorManagerTestCase extends LightPlatformCodeInsight protected VirtualFile getFile(String path) { return LocalFileSystem.getInstance().refreshAndFindFileByPath(getTestDataPath() + path); } + + protected void openFiles(String s) throws IOException, JDOMException, InterruptedException, ExecutionException { + Document document = JDOMUtil.loadDocument(s); + Element rootElement = document.getRootElement(); + ExpandMacroToPathMap map = new ExpandMacroToPathMap(); + map.addMacroExpand(PathMacroUtil.PROJECT_DIR_MACRO_NAME, getTestDataPath()); + map.substitute(rootElement, true, true); + + myManager.readExternal(rootElement); + + Future<?> future = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + myManager.getMainSplitters().openFiles(); + } + }); + while (true) { + try { + future.get(100, TimeUnit.MILLISECONDS); + return; + } + catch (TimeoutException e) { + UIUtil.dispatchAllInvocationEvents(); + } + } + } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java new file mode 100644 index 000000000000..2fe27875e2e9 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java @@ -0,0 +1,39 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.fileTypes; + +import com.intellij.openapi.file.exclude.EnforcedPlainTextFileTypeFactory; +import com.intellij.openapi.file.exclude.EnforcedPlainTextFileTypeManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; + +/** + * @author Rustam Vishnyakov + */ +public class EnforcedPlaintTextFileTypeManagerTest extends LightPlatformCodeInsightFixtureTestCase { + public void testMarkAsPlainText() { + EnforcedPlainTextFileTypeManager manager = EnforcedPlainTextFileTypeManager.getInstance(); + VirtualFile file = myFixture.getTempDirFixture().createFile("test.java"); + FileType originalType = file.getFileType(); + assertEquals("JAVA", originalType.getName()); + manager.markAsPlainText(file); + FileType changedType = file.getFileType(); + assertEquals(EnforcedPlainTextFileTypeFactory.ENFORCED_PLAIN_TEXT, changedType.getName()); + manager.resetOriginalFileType(file); + FileType revertedType = file.getFileType(); + assertEquals(originalType, revertedType); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/remotesdk/RemoteFileTest.java b/platform/platform-tests/testSrc/com/intellij/remotesdk/RemoteFileTest.java index d53ae4af054a..7133c987f4b0 100644 --- a/platform/platform-tests/testSrc/com/intellij/remotesdk/RemoteFileTest.java +++ b/platform/platform-tests/testSrc/com/intellij/remotesdk/RemoteFileTest.java @@ -15,6 +15,8 @@ */ package com.intellij.remotesdk; +import com.intellij.remote.RemoteFile; +import com.intellij.remote.RemoteSdkCredentialsHolder; import junit.framework.TestCase; /** diff --git a/platform/platform-tests/testSrc/com/intellij/util/io/PersistentMapTest.java b/platform/platform-tests/testSrc/com/intellij/util/io/PersistentMapTest.java index f40716bbecc8..7a4173039a8c 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/io/PersistentMapTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/io/PersistentMapTest.java @@ -1,3 +1,18 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.util.io; import com.intellij.openapi.util.io.FileUtil; @@ -8,6 +23,7 @@ import com.intellij.util.containers.IntObjectCache; import com.intellij.util.io.storage.AbstractStorage; import gnu.trove.THashSet; import junit.framework.TestCase; +import org.jetbrains.annotations.NotNull; import java.io.*; import java.util.*; @@ -424,13 +440,13 @@ public class PersistentMapTest extends TestCase { FileUtil.createParentDirs(file); EnumeratorStringDescriptor stringDescriptor = new EnumeratorStringDescriptor(); class PathCollectionExternalizer implements DataExternalizer<Collection<String>> { - public void save(DataOutput out, Collection<String> value) throws IOException { + public void save(@NotNull DataOutput out, Collection<String> value) throws IOException { for (String str : value) { IOUtil.writeString(str, out); } } - public Collection<String> read(DataInput in) throws IOException { + public Collection<String> read(@NotNull DataInput in) throws IOException { final Set<String> result = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY); final DataInputStream stream = (DataInputStream)in; while (stream.available() > 0) { diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectRootManager.java b/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectRootManager.java index 8d1ef81ba057..c0ed5c0ba3e1 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectRootManager.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectRootManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ public abstract class ProjectRootManager implements ModificationTracker { * @param project the project for which the instance is requested. * @return the instance. */ - public static ProjectRootManager getInstance(Project project) { + public static ProjectRootManager getInstance(@NotNull Project project) { final ProjectRootManager service = ServiceManager.getService(project, ProjectRootManager.class); if (service != null) return service; return project.getComponent(ProjectRootManager.class); diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreModule.java b/platform/projectModel-impl/src/com/intellij/core/CoreModule.java index 86fbdf7275d7..fc4f2de73b36 100644 --- a/platform/projectModel-impl/src/com/intellij/core/CoreModule.java +++ b/platform/projectModel-impl/src/com/intellij/core/CoreModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -177,51 +177,61 @@ public class CoreModule extends MockComponentManager implements ModuleEx { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleScope() { return myModuleScopeProvider.getModuleScope(); } + @NotNull @Override public GlobalSearchScope getModuleScope(boolean includeTests) { return myModuleScopeProvider.getModuleScope(includeTests); } + @NotNull @Override public GlobalSearchScope getModuleWithLibrariesScope() { return myModuleScopeProvider.getModuleWithLibrariesScope(); } + @NotNull @Override public GlobalSearchScope getModuleWithDependenciesScope() { return myModuleScopeProvider.getModuleWithDependenciesScope(); } + @NotNull @Override public GlobalSearchScope getModuleContentScope() { return myModuleScopeProvider.getModuleContentScope(); } + @NotNull @Override public GlobalSearchScope getModuleContentWithDependenciesScope() { return myModuleScopeProvider.getModuleContentWithDependenciesScope(); } + @NotNull @Override public GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(boolean includeTests) { return myModuleScopeProvider.getModuleWithDependenciesAndLibrariesScope(includeTests); } + @NotNull @Override public GlobalSearchScope getModuleWithDependentsScope() { return myModuleScopeProvider.getModuleWithDependentsScope(); } + @NotNull @Override public GlobalSearchScope getModuleTestsWithDependentsScope() { return myModuleScopeProvider.getModuleTestsWithDependentsScope(); } + @NotNull @Override public GlobalSearchScope getModuleRuntimeScope(boolean includeTests) { return myModuleScopeProvider.getModuleRuntimeScope(includeTests); diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreModuleScopeProvider.java b/platform/projectModel-impl/src/com/intellij/core/CoreModuleScopeProvider.java index aeafc197aed5..1473232df5db 100644 --- a/platform/projectModel-impl/src/com/intellij/core/CoreModuleScopeProvider.java +++ b/platform/projectModel-impl/src/com/intellij/core/CoreModuleScopeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.intellij.core; import com.intellij.openapi.module.impl.ModuleScopeProvider; import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; /** * Author: dmitrylomov @@ -25,51 +26,61 @@ public class CoreModuleScopeProvider implements ModuleScopeProvider { public CoreModuleScopeProvider() { } + @NotNull @Override public GlobalSearchScope getModuleScope() { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleScope(boolean includeTests) { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleWithLibrariesScope() { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleWithDependenciesScope() { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleContentScope() { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleContentWithDependenciesScope() { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(boolean includeTests) { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleWithDependentsScope() { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleTestsWithDependentsScope() { throw new UnsupportedOperationException(); } + @NotNull @Override public GlobalSearchScope getModuleRuntimeScope(boolean includeTests) { throw new UnsupportedOperationException(); diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java index 6041f613f1a0..9cabfb68416b 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.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. @@ -477,10 +477,7 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project @Override @NotNull - public Module loadModule(@NotNull String filePath) throws InvalidDataException, - IOException, - JDOMException, - ModuleWithNameAlreadyExists { + public Module loadModule(@NotNull String filePath) throws InvalidDataException, IOException, JDOMException, ModuleWithNameAlreadyExists { myModificationCount++; final ModifiableModuleModel modifiableModel = getModifiableModel(); final Module module = modifiableModel.loadModule(filePath); @@ -745,10 +742,9 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project } } - private Module loadModuleInternal(String filePath) - throws ModuleWithNameAlreadyExists, IOException, StateStorageException { - - final VirtualFile moduleFile = StandardFileSystems.local().findFileByPath(resolveShortWindowsName(filePath)); + private Module loadModuleInternal(String filePath) throws ModuleWithNameAlreadyExists, IOException, StateStorageException { + filePath = resolveShortWindowsName(filePath); + final VirtualFile moduleFile = StandardFileSystems.local().findFileByPath(filePath); if (moduleFile == null || !moduleFile.exists()) { throw new IOException(ProjectBundle.message("module.file.does.not.exist.error", filePath)); } diff --git a/platform/remote-servers/impl/resources/resources/cloud.properties b/platform/remote-servers/impl/resources/resources/cloud.properties index f7637990f0d8..24aae89b33a7 100644 --- a/platform/remote-servers/impl/resources/resources/cloud.properties +++ b/platform/remote-servers/impl/resources/resources/cloud.properties @@ -5,4 +5,4 @@ failed.add.remote=Failed to add {0} repository as remote failed.reset.remote=Failed to set {0} repository as remote cloning.existing.application=Cloning existing {0} application fetching.application=Fetching {0} application - +run.configuration.name={0} - {1} diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudAccountSelectionEditor.form b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudAccountSelectionEditor.form new file mode 100644 index 000000000000..bbfd6da1afcc --- /dev/null +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudAccountSelectionEditor.form @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.remoteServer.util.CloudAccountSelectionEditor"> + <grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <xy x="20" y="20" width="500" height="400"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="82588" class="javax.swing.JComboBox" binding="myServerComboBox"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + </component> + <grid id="27f9c" binding="myServerConfigurablePanel" custom-create="true" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children/> + </grid> + <vspacer id="dcc88"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + </constraints> + </vspacer> + </children> + </grid> +</form> diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudAccountSelectionEditor.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudAccountSelectionEditor.java new file mode 100644 index 000000000000..aab46e76a3c7 --- /dev/null +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudAccountSelectionEditor.java @@ -0,0 +1,222 @@ +/* + * 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. + * 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.remoteServer.util; + +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModulePointer; +import com.intellij.openapi.module.ModulePointerManager; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.remoteServer.ServerType; +import com.intellij.remoteServer.configuration.RemoteServer; +import com.intellij.remoteServer.configuration.RemoteServersManager; +import com.intellij.remoteServer.impl.configuration.RemoteServerConfigurable; +import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerConfigurationType; +import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerRunConfiguration; +import com.intellij.remoteServer.impl.configuration.deployment.ModuleDeploymentSourceImpl; +import com.intellij.util.text.UniqueNameGenerator; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * @author michael.golubev + */ +public class CloudAccountSelectionEditor<SC extends CloudConfigurationBase, + DC extends CloudDeploymentNameConfiguration, + ST extends ServerType<SC>> implements Disposable { + + private static final Logger LOG = Logger.getInstance("#" + CloudAccountSelectionEditor.class.getName()); + + private JComboBox myServerComboBox; + private JPanel myServerConfigurablePanel; + private JPanel myMainPanel; + + private final ST myCloudType; + + private RemoteServer<SC> myNewServer; + private RemoteServerConfigurable myServerConfigurable; + + protected CloudAccountSelectionEditor(ST cloudType) { + myCloudType = cloudType; + } + + private void createUIComponents() { + myServerConfigurablePanel = createServerConfigurablePanel(); + } + + public void initUI() { + myServerComboBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + onAccountSelectionChanged(); + } + }); + + for (RemoteServer<SC> server : RemoteServersManager.getInstance().getServers(myCloudType)) { + myServerComboBox.addItem(new ServerItem(server)); + } + myServerComboBox.addItem(new ServerItem(myNewServer)); + } + + private void onAccountSelectionChanged() { + myServerConfigurablePanel.setVisible(getSelectedServerItem().isNew()); + } + + protected JPanel createServerConfigurablePanel() { + myNewServer = RemoteServersManager.getInstance().createServer(myCloudType, generateServerName()); + myServerConfigurable = new RemoteServerConfigurable(myNewServer, null, true); + myServerConfigurablePanel = (JPanel)myServerConfigurable.createComponent(); + return myServerConfigurablePanel; + } + + private String generateServerName() { + return UniqueNameGenerator.generateUniqueName(myCloudType.getPresentableName(), new Condition<String>() { + + @Override + public boolean value(String s) { + for (RemoteServer<?> server : RemoteServersManager.getInstance().getServers()) { + if (server.getName().equals(s)) { + return false; + } + } + return true; + } + }); + } + + public DeployToServerRunConfiguration<SC, DC> createRunConfiguration(Module module, DC deploymentConfiguration) { + Project project = module.getProject(); + + RemoteServer<SC> server = getServer(); + if (server == null) { + return null; + } + + if (getSelectedServerItem().isNew()) { + RemoteServersManager.getInstance().addServer(server); + } + + String serverName = server.getName(); + + String name = generateRunConfigurationName(serverName, module.getName()); + + final RunManagerEx runManager = RunManagerEx.getInstanceEx(project); + final RunnerAndConfigurationSettings runSettings + = runManager.createRunConfiguration(name, getRunConfigurationType().getConfigurationFactories()[0]); + + final DeployToServerRunConfiguration<SC, DC> result = (DeployToServerRunConfiguration<SC, DC>)runSettings.getConfiguration(); + + runManager.addConfiguration(runSettings, false); + runManager.setSelectedConfiguration(runSettings); + + result.setServerName(serverName); + + final ModulePointer modulePointer = ModulePointerManager.getInstance(project).create(module); + result.setDeploymentSource(new ModuleDeploymentSourceImpl(modulePointer)); + + result.setDeploymentConfiguration(deploymentConfiguration); + + return result; + } + + protected String generateRunConfigurationName(String serverName, String moduleName) { + return CloudBundle.getText("run.configuration.name", serverName, moduleName); + } + + protected void handleError(ConfigurationException e) { + LOG.info(e); + } + + public RemoteServer<SC> getServer() { + try { + return doGetServer(); + } + catch (ConfigurationException e) { + handleError(e); + return null; + } + } + + private RemoteServer<SC> doGetServer() throws ConfigurationException { + ServerItem serverItem = getSelectedServerItem(); + if (serverItem.isNew()) { + myServerConfigurable.apply(); + myNewServer.setName(myServerConfigurable.getDisplayName()); + } + return serverItem.getServer(); + } + + public void validate() throws ConfigurationException { + doGetServer(); + } + + private ServerItem getSelectedServerItem() { + return (ServerItem)myServerComboBox.getSelectedItem(); + } + + private DeployToServerConfigurationType getRunConfigurationType() { + String id = DeployToServerConfigurationType.getId(myCloudType); + for (ConfigurationType configurationType : ConfigurationType.CONFIGURATION_TYPE_EP.getExtensions()) { + if (configurationType instanceof DeployToServerConfigurationType) { + DeployToServerConfigurationType deployConfigurationType = (DeployToServerConfigurationType)configurationType; + if (deployConfigurationType.getId().equals(id)) { + return deployConfigurationType; + } + } + } + return null; + } + + public JPanel getMainPanel() { + return myMainPanel; + } + + @Override + public void dispose() { + myServerConfigurable.disposeUIResources(); + } + + private class ServerItem { + + private final RemoteServer<SC> myServer; + + public ServerItem(RemoteServer<SC> server) { + myServer = server; + } + + public boolean isNew() { + return myServer == myNewServer; + } + + public RemoteServer<SC> getServer() { + return myServer; + } + + @Override + public String toString() { + return isNew() ? "New account..." : myServer.getName(); + } + } +} diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSupportConfigurableBase.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSupportConfigurableBase.java index e27a892594f3..4aecb257f7b4 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSupportConfigurableBase.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSupportConfigurableBase.java @@ -1,39 +1,24 @@ package com.intellij.remoteServer.util; import com.intellij.ProjectTopics; -import com.intellij.execution.RunManagerEx; -import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.configurations.ConfigurationType; import com.intellij.ide.util.frameworkSupport.FrameworkSupportConfigurable; import com.intellij.ide.util.frameworkSupport.FrameworkSupportModel; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModulePointer; -import com.intellij.openapi.module.ModulePointerManager; -import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.ModuleAdapter; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.util.Condition; -import com.intellij.remoteServer.ServerType; +import com.intellij.openapi.util.Disposer; import com.intellij.remoteServer.configuration.RemoteServer; -import com.intellij.remoteServer.configuration.RemoteServersManager; -import com.intellij.remoteServer.impl.configuration.RemoteServerConfigurable; -import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerConfigurationType; -import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerRunConfiguration; -import com.intellij.remoteServer.impl.configuration.deployment.ModuleDeploymentSourceImpl; import com.intellij.remoteServer.runtime.Deployment; import com.intellij.remoteServer.runtime.ServerConnection; import com.intellij.remoteServer.runtime.ServerConnector; import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.messages.MessageBusConnection; -import com.intellij.util.text.UniqueNameGenerator; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.Collection; import java.util.concurrent.atomic.AtomicReference; @@ -43,43 +28,24 @@ import java.util.concurrent.atomic.AtomicReference; public abstract class CloudSupportConfigurableBase< SC extends CloudConfigurationBase, DC extends CloudDeploymentNameConfiguration, - ST extends ServerType<SC>, SR extends CloudMultiSourceServerRuntimeInstance<DC, ?, ?, ?>> extends FrameworkSupportConfigurable { private final Project myModelProject; - private RemoteServer<SC> myNewServer; - private ST myCloudType; - private RemoteServerConfigurable myServerConfigurable; - private JPanel myServerConfigurablePanel; private boolean myInitialized = false; - public CloudSupportConfigurableBase(FrameworkSupportModel frameworkSupportModel, ST cloudType) { + public CloudSupportConfigurableBase(FrameworkSupportModel frameworkSupportModel) { myModelProject = frameworkSupportModel.getProject(); - myCloudType = cloudType; } @Override public void dispose() { - myServerConfigurable.disposeUIResources(); + Disposer.dispose(getAccountSelectionEditor()); } protected void initUI() { - JComboBox serverComboBox = getServerComboBox(); - - serverComboBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - onAccountSelectionChanged(); - } - }); - - for (RemoteServer<SC> server : RemoteServersManager.getInstance().getServers(myCloudType)) { - serverComboBox.addItem(new ServerItem(server)); - } - serverComboBox.addItem(new ServerItem(myNewServer)); + getAccountSelectionEditor().initUI(); } protected void reloadExistingApplications() { @@ -137,21 +103,6 @@ public abstract class CloudSupportConfigurableBase< } } - private ServerItem getSelectedServerItem() { - return (ServerItem)getServerComboBox().getSelectedItem(); - } - - private void onAccountSelectionChanged() { - myServerConfigurablePanel.setVisible(getSelectedServerItem().isNew()); - } - - protected JPanel createServerConfigurablePanel() { - myNewServer = RemoteServersManager.getInstance().createServer(myCloudType, generateServerName()); - myServerConfigurable = new RemoteServerConfigurable(myNewServer, null, true); - myServerConfigurablePanel = (JPanel)myServerConfigurable.createComponent(); - return myServerConfigurablePanel; - } - protected void showMessage(String message, MessageType messageType) { getNotifier().showMessage(message, messageType); } @@ -160,77 +111,8 @@ public abstract class CloudSupportConfigurableBase< return myModelProject; } - private String generateServerName() { - return UniqueNameGenerator.generateUniqueName(myCloudType.getPresentableName(), new Condition<String>() { - - @Override - public boolean value(String s) { - for (RemoteServer<?> server : RemoteServersManager.getInstance().getServers()) { - if (server.getName().equals(s)) { - return false; - } - } - return true; - } - }); - } - - private DeployToServerConfigurationType getRunConfigurationType() { - String id = DeployToServerConfigurationType.getId(myCloudType); - for (ConfigurationType configurationType : ConfigurationType.CONFIGURATION_TYPE_EP.getExtensions()) { - if (configurationType instanceof DeployToServerConfigurationType) { - DeployToServerConfigurationType deployConfigurationType = (DeployToServerConfigurationType)configurationType; - if (deployConfigurationType.getId().equals(id)) { - return deployConfigurationType; - } - } - } - return null; - } - protected RemoteServer<SC> getServer() { - ServerItem serverItem = getSelectedServerItem(); - if (serverItem.isNew()) { - try { - myServerConfigurable.apply(); - myNewServer.setName(myServerConfigurable.getDisplayName()); - } - catch (ConfigurationException e) { - showMessage(e.getMessage(), MessageType.ERROR); - return null; - } - } - return serverItem.getServer(); - } - - protected DeployToServerRunConfiguration<SC, DC> createRunConfiguration(String name, Module module, DC deploymentConfiguration) { - Project project = module.getProject(); - - RemoteServer<SC> server = getServer(); - - if (getSelectedServerItem().isNew()) { - RemoteServersManager.getInstance().addServer(server); - } - - String serverName = server.getName(); - - final RunManagerEx runManager = RunManagerEx.getInstanceEx(project); - final RunnerAndConfigurationSettings runSettings - = runManager.createRunConfiguration(name, getRunConfigurationType().getConfigurationFactories()[0]); - - final DeployToServerRunConfiguration<SC, DC> result = (DeployToServerRunConfiguration<SC, DC>)runSettings.getConfiguration(); - - runManager.addConfiguration(runSettings, false); - runManager.setSelectedConfiguration(runSettings); - - result.setServerName(serverName); - - final ModulePointer modulePointer = ModulePointerManager.getInstance(project).create(module); - result.setDeploymentSource(new ModuleDeploymentSourceImpl(modulePointer)); - - result.setDeploymentConfiguration(deploymentConfiguration); - - return result; + return getAccountSelectionEditor().getServer(); } protected void runOnModuleAdded(final Module module, final Runnable runnable) { @@ -250,36 +132,14 @@ public abstract class CloudSupportConfigurableBase< } } - protected abstract JComboBox getExistingComboBox(); + protected abstract CloudAccountSelectionEditor<SC, DC, ?> getAccountSelectionEditor(); - protected abstract JComboBox getServerComboBox(); + protected abstract JComboBox getExistingComboBox(); protected abstract void updateApplicationUI(); protected abstract CloudNotifier getNotifier(); - protected class ServerItem { - - private final RemoteServer<SC> myServer; - - public ServerItem(RemoteServer<SC> server) { - myServer = server; - } - - public boolean isNew() { - return myServer == myNewServer; - } - - public RemoteServer<SC> getServer() { - return myServer; - } - - @Override - public String toString() { - return isNew() ? "New account..." : myServer.getName(); - } - } - protected abstract class ConnectionTask<T> extends CloudConnectionTask<T, SC, DC, SR> { public ConnectionTask(String title) { diff --git a/platform/structure-view-api/src/com/intellij/ide/structureView/TextEditorBasedStructureViewModel.java b/platform/structure-view-api/src/com/intellij/ide/structureView/TextEditorBasedStructureViewModel.java index 5cef3a5801a6..34641fe63557 100644 --- a/platform/structure-view-api/src/com/intellij/ide/structureView/TextEditorBasedStructureViewModel.java +++ b/platform/structure-view-api/src/com/intellij/ide/structureView/TextEditorBasedStructureViewModel.java @@ -19,8 +19,8 @@ import com.intellij.ide.util.treeView.smartTree.*; import com.intellij.openapi.Disposable; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.event.CaretAdapter; import com.intellij.openapi.editor.event.CaretEvent; -import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.util.Disposer; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -71,7 +71,7 @@ public abstract class TextEditorBasedStructureViewModel implements StructureView myPsiFile = file; if (editor != null) { - EditorFactory.getInstance().getEventMulticaster().addCaretListener(new CaretListener() { + EditorFactory.getInstance().getEventMulticaster().addCaretListener(new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { if (e.getEditor().equals(myEditor)) { diff --git a/platform/testFramework/src/com/intellij/mock/Mock.java b/platform/testFramework/src/com/intellij/mock/Mock.java index d511f2fd2d35..f0ca6a19e745 100644 --- a/platform/testFramework/src/com/intellij/mock/Mock.java +++ b/platform/testFramework/src/com/intellij/mock/Mock.java @@ -453,9 +453,10 @@ public class Mock { throw new UnsupportedOperationException(); } + @NotNull @Override public String getPath() { - return null; + throw new UnsupportedOperationException(); } @Override diff --git a/platform/testFramework/src/com/intellij/mock/MockModule.java b/platform/testFramework/src/com/intellij/mock/MockModule.java index 9a0065c2115c..e0eaf7aac476 100644 --- a/platform/testFramework/src/com/intellij/mock/MockModule.java +++ b/platform/testFramework/src/com/intellij/mock/MockModule.java @@ -1,5 +1,17 @@ /* - * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved. + * 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. + * 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.mock; @@ -37,26 +49,31 @@ public class MockModule extends MockComponentManager implements Module { return ""; } + @NotNull @Override public GlobalSearchScope getModuleRuntimeScope(final boolean includeTests) { return new MockGlobalSearchScope(); } + @NotNull @Override public GlobalSearchScope getModuleScope() { return new MockGlobalSearchScope(); } + @NotNull @Override public GlobalSearchScope getModuleScope(boolean includeTests) { return new MockGlobalSearchScope(); } + @NotNull @Override public GlobalSearchScope getModuleTestsWithDependentsScope() { return new MockGlobalSearchScope(); } + @NotNull @Override public GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(final boolean includeTests) { return new MockGlobalSearchScope(); @@ -64,26 +81,31 @@ public class MockModule extends MockComponentManager implements Module { //throw new UnsupportedOperationException( "Method getModuleWithDependenciesAndLibrariesScope is not yet implemented in " + getClass().getName()); } + @NotNull @Override public GlobalSearchScope getModuleWithDependenciesScope() { return new MockGlobalSearchScope(); } + @NotNull @Override public GlobalSearchScope getModuleContentWithDependenciesScope() { throw new UnsupportedOperationException("Method getModuleContentWithDependenciesScope is not yet implemented in " + getClass().getName()); } + @NotNull @Override public GlobalSearchScope getModuleContentScope() { throw new UnsupportedOperationException("Method getModuleContentScope is not yet implemented in " + getClass().getName()); } + @NotNull @Override public GlobalSearchScope getModuleWithDependentsScope() { throw new UnsupportedOperationException("Method getModuleWithDependentsScope is not yet implemented in " + getClass().getName()); } + @NotNull @Override public GlobalSearchScope getModuleWithLibrariesScope() { throw new UnsupportedOperationException("Method getModuleWithLibrariesScope is not yet implemented in " + getClass().getName()); diff --git a/platform/testFramework/src/com/intellij/mock/MockVirtualFile.java b/platform/testFramework/src/com/intellij/mock/MockVirtualFile.java index f6c02f5930ee..9f31bbb9b10f 100644 --- a/platform/testFramework/src/com/intellij/mock/MockVirtualFile.java +++ b/platform/testFramework/src/com/intellij/mock/MockVirtualFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -90,6 +90,7 @@ public class MockVirtualFile extends VirtualFile { return ourFileSystem; } + @NotNull @Override public String getPath() { String prefix = myParent == null ? "MOCK_ROOT:" : myParent.getPath(); @@ -101,6 +102,7 @@ public class MockVirtualFile extends VirtualFile { return myIsWritable; } + @Override public void setWritable(boolean b) { myIsWritable = b; } diff --git a/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java b/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java index 2eeee2eb0ac7..19870bfe9b33 100644 --- a/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java +++ b/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.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. @@ -113,9 +113,10 @@ public class MockVirtualFileSystem extends DeprecatedVirtualFileSystem { @Override public boolean isDirectory() { - return myChildren.size() != 0; + return !myChildren.isEmpty(); } + @NotNull @Override public String getPath() { final MockVirtualFileSystem.MyVirtualFile parent = getParent(); diff --git a/platform/testFramework/testSrc/com/intellij/psi/formatter/FormatterTestCase.java b/platform/testFramework/src/com/intellij/psi/formatter/FormatterTestCase.java index 2afd09168420..2afd09168420 100644 --- a/platform/testFramework/testSrc/com/intellij/psi/formatter/FormatterTestCase.java +++ b/platform/testFramework/src/com/intellij/psi/formatter/FormatterTestCase.java diff --git a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java index 5d658bfe7e3a..3ae9b8d1c69b 100644 --- a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java @@ -30,7 +30,6 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.editor.impl.DefaultEditorTextRepresentationHelper; import com.intellij.openapi.editor.impl.SoftWrapModelImpl; import com.intellij.openapi.editor.impl.softwrap.mapping.SoftWrapApplianceManager; -import com.intellij.openapi.util.Segment; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -309,13 +308,13 @@ public class EditorTestUtil { public static void setCaretsAndSelection(Editor editor, CaretAndSelectionState caretsState) { CaretModel caretModel = editor.getCaretModel(); if (caretModel.supportsMultipleCarets()) { - List<LogicalPosition> caretPositions = new ArrayList<LogicalPosition>(); - List<Segment> selections = new ArrayList<Segment>(); + List<CaretState> states = new ArrayList<CaretState>(caretsState.carets.size()); for (CaretInfo caret : caretsState.carets) { - caretPositions.add(caret.position == null ? null : editor.offsetToLogicalPosition(caret.getCaretOffset(editor.getDocument()))); - selections.add(caret.selection == null ? null : caret.selection); + states.add(new CaretState(caret.position == null ? null : editor.offsetToLogicalPosition(caret.getCaretOffset(editor.getDocument())), + caret.selection == null ? null : editor.offsetToLogicalPosition(caret.selection.getStartOffset()), + caret.selection == null ? null : editor.offsetToLogicalPosition(caret.selection.getEndOffset()))); } - caretModel.setCaretsAndSelections(caretPositions, selections); + caretModel.setCaretsAndSelections(states); } else { assertEquals("Multiple carets are not supported by the model", 1, caretsState.carets.size()); @@ -326,6 +325,9 @@ public class EditorTestUtil { if (caret.selection != null) { editor.getSelectionModel().setSelection(caret.selection.getStartOffset(), caret.selection.getEndOffset()); } + else { + editor.getSelectionModel().removeSelection(); + } } if (caretsState.blockSelection != null) { editor.getSelectionModel().setBlockSelection(editor.offsetToLogicalPosition(caretsState.blockSelection.getStartOffset()), diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index e1e6907985a4..59b8d4b95056 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -308,14 +308,14 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro protected static Module doCreateRealModuleIn(String moduleName, final Project project, final ModuleType moduleType) { final VirtualFile baseDir = project.getBaseDir(); assertNotNull(baseDir); - final File moduleFile = new File(baseDir.getPath().replace('/', File.separatorChar), - moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION); + final File moduleFile = new File(FileUtil.toSystemDependentName(baseDir.getPath()), moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION); FileUtil.createIfDoesntExist(moduleFile); myFilesToDelete.add(moduleFile); return new WriteAction<Module>() { @Override - protected void run(Result<Module> result) throws Throwable { - final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(moduleFile); + protected void run(@NotNull Result<Module> result) throws Throwable { + VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(moduleFile); + assertNotNull(virtualFile); Module module = ModuleManager.getInstance(project).newModule(virtualFile.getPath(), moduleType.getId()); module.getModuleFile(); result.setResult(module); diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 785c587f488f..104c55e0c77b 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -639,6 +639,14 @@ public abstract class UsefulTestCase extends TestCase { String actualText = StringUtil.convertLineSeparators(actual.trim()); Assert.assertEquals(expectedText, actualText); } + + public static void assertExists(File file){ + assertTrue("File should exists " + file, file.exists()); + } + + public static void assertDoesntExist(File file){ + assertFalse("File should not exists " + file, file.exists()); + } protected String getTestName(boolean lowercaseFirstLetter) { String name = getName(); diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index 0c24d8b534b4..af4c7f6f35ab 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -817,8 +817,11 @@ public class AllIcons { public static final Icon Parameter = IconLoader.getIcon("/nodes/parameter.png"); // 16x16 public static final Icon PinToolWindow = IconLoader.getIcon("/nodes/pinToolWindow.png"); // 13x13 public static final Icon Plugin = IconLoader.getIcon("/nodes/plugin.png"); // 16x16 + public static final Icon PluginJB = IconLoader.getIcon("/nodes/pluginJB.png"); // 16x16 public static final Icon Pluginnotinstalled = IconLoader.getIcon("/nodes/pluginnotinstalled.png"); // 16x16 public static final Icon Pluginobsolete = IconLoader.getIcon("/nodes/pluginobsolete.png"); // 16x16 + public static final Icon PluginRestart = IconLoader.getIcon("/nodes/pluginRestart.png"); // 16x16 + public static final Icon PluginUpdate = IconLoader.getIcon("/nodes/pluginUpdate.png"); // 16x16 public static final Icon Pointcut = IconLoader.getIcon("/nodes/pointcut.png"); // 16x16 public static final Icon PpFile = IconLoader.getIcon("/nodes/ppFile.png"); // 16x16 public static final Icon PpInvalid = IconLoader.getIcon("/nodes/ppInvalid.png"); // 16x16 diff --git a/platform/util/src/com/intellij/openapi/diff/LineTokenizer.java b/platform/util/src/com/intellij/openapi/diff/LineTokenizer.java index 7aafcacf7fbb..e86567bde782 100644 --- a/platform/util/src/com/intellij/openapi/diff/LineTokenizer.java +++ b/platform/util/src/com/intellij/openapi/diff/LineTokenizer.java @@ -17,18 +17,14 @@ package com.intellij.openapi.diff; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; -public class LineTokenizer { +public class LineTokenizer extends LineTokenizerBase<String> { private final char[] myChars; private final String myText; - private int myIndex = 0; - @Nullable private String myLineSeparator = null; - public LineTokenizer(@NotNull String text) { myChars = text.toCharArray(); myText = text; @@ -36,71 +32,35 @@ public class LineTokenizer { @NotNull public String[] execute() { - List<String> lines = new ArrayList<String>(); - while (notAtEnd()) { - int begin = myIndex; - skipToEOL(); - int endIndex = myIndex; - boolean appendNewLine = false; - - if (notAtEnd() && isAtEOL()) { - if (myChars[endIndex] == '\n') { - endIndex++; - } - else { - appendNewLine = true; - } - skipEOL(); - } - - String line = myText.substring(begin, endIndex); - if (appendNewLine) { - line += "\n"; - } - lines.add(line); - } + ArrayList<String> lines = new ArrayList<String>(); + doExecute(lines); return ArrayUtil.toStringArray(lines); } - private void skipEOL() { - int eolStart = myIndex; - boolean nFound = false; - boolean rFound = false; - while (notAtEnd()) { - boolean n = myChars[myIndex] == '\n'; - boolean r = myChars[myIndex] == '\r'; - if (!n && !r) { - break; - } - if ((nFound && n) || (rFound && r)) { - break; - } - nFound |= n; - rFound |= r; - myIndex++; + @Override + protected void addLine(List<String> lines, int start, int end, boolean appendNewLine) { + if (appendNewLine) { + lines.add(myText.substring(start, end) + "\n"); } - if (myLineSeparator == null) { - myLineSeparator = new String(myChars, eolStart, myIndex - eolStart); + else { + lines.add(myText.substring(start, end)); } } - @Nullable - public String getLineSeparator() { - return myLineSeparator; + @Override + protected char charAt(int index) { + return myChars[index]; } - private void skipToEOL() { - while (notAtEnd() && !isAtEOL()) { - myIndex++; - } - } - - private boolean notAtEnd() { - return myIndex < myChars.length; + @Override + protected int length() { + return myChars.length; } - private boolean isAtEOL() { - return myChars[myIndex] == '\r' || myChars[myIndex] == '\n'; + @NotNull + @Override + protected String substring(int start, int end) { + return myText.substring(start, end); } @NotNull diff --git a/platform/util/src/com/intellij/openapi/diff/LineTokenizerBase.java b/platform/util/src/com/intellij/openapi/diff/LineTokenizerBase.java new file mode 100644 index 000000000000..85fed352e819 --- /dev/null +++ b/platform/util/src/com/intellij/openapi/diff/LineTokenizerBase.java @@ -0,0 +1,100 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.diff; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public abstract class LineTokenizerBase<T> { + private int myIndex = 0; + private int myLineSeparatorStart = -1; + private int myLineSeparatorEnd = -1; + + protected abstract void addLine(List<T> lines, int start, int end, boolean appendNewLine); + + protected abstract char charAt(int index); + + protected abstract int length(); + + @NotNull + protected abstract String substring(int start, int end); + + public void doExecute(List<T> lines) { + while (notAtEnd()) { + int begin = myIndex; + skipToEOL(); + int endIndex = myIndex; + boolean appendNewLine = false; + + if (notAtEnd() && isAtEOL()) { + if (charAt(endIndex) == '\n') { + endIndex++; + } + else { + appendNewLine = true; + } + skipEOL(); + } + + addLine(lines, begin, endIndex, appendNewLine); + } + } + + private void skipEOL() { + int eolStart = myIndex; + boolean nFound = false; + boolean rFound = false; + while (notAtEnd()) { + boolean n = charAt(myIndex) == '\n'; + boolean r = charAt(myIndex) == '\r'; + if (!n && !r) { + break; + } + if ((nFound && n) || (rFound && r)) { + break; + } + nFound |= n; + rFound |= r; + myIndex++; + } + if (myLineSeparatorStart == -1) { + myLineSeparatorStart = eolStart; + myLineSeparatorEnd = myIndex; + } + } + + @Nullable + public String getLineSeparator() { + if (myLineSeparatorStart == -1) return null; + return substring(myLineSeparatorStart, myLineSeparatorEnd); + } + + private void skipToEOL() { + while (notAtEnd() && !isAtEOL()) { + myIndex++; + } + } + + private boolean notAtEnd() { + return myIndex < length(); + } + + private boolean isAtEOL() { + return charAt(myIndex) == '\r' || charAt(myIndex) == '\n'; + } +}
\ No newline at end of file diff --git a/platform/util/src/com/intellij/openapi/diff/ex/DiffFragment.java b/platform/util/src/com/intellij/openapi/diff/ex/DiffFragment.java index 791d4a0c46e1..e1a4852affe0 100644 --- a/platform/util/src/com/intellij/openapi/diff/ex/DiffFragment.java +++ b/platform/util/src/com/intellij/openapi/diff/ex/DiffFragment.java @@ -15,31 +15,37 @@ */ package com.intellij.openapi.diff.ex; +import com.intellij.openapi.diff.impl.string.DiffString; +import com.intellij.openapi.diff.impl.string.DiffStringBuilder; import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; public class DiffFragment { public static DiffFragment[] EMPTY_ARRAY = new DiffFragment[0]; - private final String myText1; - private final String myText2; + @Nullable private CharSequence myText1; + @Nullable private CharSequence myText2; private boolean myIsModified; - private StringBuilder myText1Builder; - private StringBuilder myText2Builder; + @TestOnly + public DiffFragment(@Nullable String text1, @Nullable String text2) { + this(DiffString.createNullable(text1), DiffString.createNullable(text2)); + } - public DiffFragment(String text1, String text2) { + public DiffFragment(@Nullable DiffString text1, @Nullable DiffString text2) { myText1 = text1; myText2 = text2; myIsModified = (text1 == null || text2 == null || !text1.equals(text2)); } - public static boolean isEmpty(DiffFragment fragment) { - return StringUtil.length(fragment.getText1()) == 0 && - StringUtil.length(fragment.getText2()) == 0; + public boolean isEmpty() { + return StringUtil.isEmpty(myText1) && StringUtil.isEmpty(myText2); } /** - * Makes sence if both texts are not null + * Makes sense if both texts are not null * @return true if both texts are considered modified, false otherwise */ public boolean isModified() { @@ -50,34 +56,70 @@ public class DiffFragment { myIsModified = modified; } - public void appendText1(String str) { - assert myText1 != null; - if (myText1Builder == null) { - myText1Builder = new StringBuilder(myText1); + public void appendText1(@Nullable DiffString str) { + if (str == null) return; + if (myText1 instanceof DiffStringBuilder) { + ((DiffStringBuilder)myText1).append(str); + return; + } + + if (myText1 instanceof DiffString) { + DiffString text1 = (DiffString)myText1; + if (DiffString.canInplaceConcatenate(text1, str)) { + myText1 = DiffString.concatenate(text1, str); + } + else { + DiffStringBuilder builder = new DiffStringBuilder(text1.length() + str.length()); + builder.append(text1); + builder.append(str); + myText1 = builder; + } + return; } - myText1Builder.append(str); + + throw new IllegalStateException("Bad DiffFragment: " + (myText1 != null ? myText1.getClass() : "null")); } - public void appendText2(String str) { - assert myText2 != null; - if (myText2Builder == null) { - myText2Builder = new StringBuilder(myText2); + public void appendText2(@Nullable DiffString str) { + if (str == null) return; + if (myText2 instanceof DiffStringBuilder) { + ((DiffStringBuilder)myText2).append(str); + return; } - myText2Builder.append(str); + + if (myText2 instanceof DiffString) { + DiffString text2 = (DiffString)myText2; + if (DiffString.canInplaceConcatenate(text2, str)) { + myText2 = DiffString.concatenate(text2, str); + } + else { + DiffStringBuilder builder = new DiffStringBuilder(text2.length() + str.length()); + builder.append(text2); + builder.append(str); + myText2 = builder; + } + return; + } + + throw new IllegalStateException("Bad DiffFragment: " + (myText2 != null ? myText2.getClass() : "null")); } - /** - * null if absent - */ - public String getText1() { - return myText1Builder != null ? myText1Builder.toString() : myText1; + @Nullable + public DiffString getText1() { + if (myText1 == null) return null; + if (myText1 instanceof DiffString) return (DiffString)myText1; + if (myText1 instanceof DiffStringBuilder) return ((DiffStringBuilder)myText1).toDiffString(); + + throw new IllegalStateException("Bad DiffFragment: " + myText1.getClass()); } - - /** - * null if absent - */ - public String getText2() { - return myText2Builder != null ? myText2Builder.toString() : myText2; + + @Nullable + public DiffString getText2() { + if (myText2 == null) return null; + if (myText2 instanceof DiffString) return (DiffString)myText2; + if (myText2 instanceof DiffStringBuilder) return ((DiffStringBuilder)myText2).toDiffString(); + + throw new IllegalStateException("Bad DiffFragment: " + myText2.getClass()); } /** @@ -85,23 +127,30 @@ public class DiffFragment { * @return true iff both texts are present and {@link #isModified()} */ public boolean isChange() { - return myText1 != null && myText2 != null && isModified(); + return (myText1 != null) && (myText2 != null) && isModified(); } /** * @return true iff both texts are present and not {@link #isModified()} */ public boolean isEqual() { - return myText1 != null && myText2 != null && !isModified(); + return (myText1 != null) && (myText2 != null) && !isModified(); + } + + @TestOnly + public static DiffFragment unchanged(@Nullable String text1, @Nullable String text2) { + return unchanged(DiffString.createNullable(text1), DiffString.createNullable(text2)); } - public static DiffFragment unchanged(String text1, String text2) { + public static DiffFragment unchanged(@Nullable DiffString text1, @Nullable DiffString text2) { + if (text1 == null) text1 = DiffString.EMPTY; + if (text2 == null) text2 = DiffString.EMPTY; DiffFragment result = new DiffFragment(text1, text2); result.setModified(false); return result; } public boolean isOneSide() { - return myText1 == null || myText2 == null; + return (myText1 == null) || (myText2 == null); } } diff --git a/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java b/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java index 0767413e3f5b..b38c827adf9f 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff.impl; import com.intellij.CommonBundle; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.Util; @@ -24,18 +25,30 @@ import com.intellij.openapi.diff.impl.processing.Formatting; import com.intellij.openapi.diff.impl.processing.Word; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.diff.Diff; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; public abstract class ComparisonPolicy { + public static final ComparisonPolicy DEFAULT = new DefaultPolicy(); + public static final ComparisonPolicy TRIM_SPACE = new TrimSpacePolicy(); + public static final ComparisonPolicy IGNORE_SPACE = new IgnoreSpacePolicy(); + public static final ComparisonPolicy[] COMPARISON_POLICIES = new ComparisonPolicy[]{DEFAULT, IGNORE_SPACE, TRIM_SPACE}; + private final String myName; protected ComparisonPolicy(final String name) { myName = name; } - public DiffFragment[] buildFragments(String[] strings1, String[] strings2) throws FilesTooBigForDiffException { + public String getName() { + return myName; + } + + @NotNull + public DiffFragment[] buildFragments(@NotNull DiffString[] strings1, @NotNull DiffString[] strings2) throws FilesTooBigForDiffException { DiffFragmentBuilder builder = new DiffFragmentBuilder(strings1, strings2); Object[] wrappers1 = getWrappers(strings1); Object[] wrappers2 = getWrappers(strings2); @@ -43,7 +56,9 @@ public abstract class ComparisonPolicy { return builder.buildFragments(Util.concatEquals(change, wrappers1, wrappers2)); } - public DiffFragment[] buildDiffFragmentsFromLines(String[] lines1, String[] lines2) throws FilesTooBigForDiffException { + @NotNull + public DiffFragment[] buildDiffFragmentsFromLines(@NotNull DiffString[] lines1, @NotNull DiffString[] lines2) + throws FilesTooBigForDiffException { DiffFragmentBuilder builder = new DiffFragmentBuilder(lines1, lines2); Object[] wrappers1 = getLineWrappers(lines1); Object[] wrappers2 = getLineWrappers(lines2); @@ -51,19 +66,52 @@ public abstract class ComparisonPolicy { return builder.buildFragments(change); } - public static final ComparisonPolicy DEFAULT = new ComparisonPolicy(CommonBundle.message("comparison.policy.default.name")) { + @NotNull + public DiffFragment createFragment(@Nullable DiffString text1, @Nullable DiffString text2) { + text1 = toNull(text1); + text2 = toNull(text2); + if (text1 == null && text2 == null) return new DiffFragment(DiffString.EMPTY, DiffString.EMPTY); + DiffFragment result = new DiffFragment(text1, text2); + if (text1 != null && text2 != null) { + result.setModified(!getWrapper(text1).equals(getWrapper(text2))); + } + return result; + } + + @NotNull + public abstract DiffFragment createFragment(@NotNull Word word1, @NotNull Word word2); + + @NotNull + protected abstract Object[] getWrappers(@NotNull DiffString[] strings); + + @NotNull + protected abstract Object[] getLineWrappers(@NotNull DiffString[] lines); + + @NotNull + private Object getWrapper(@NotNull DiffString text) { + return getWrappers(new DiffString[]{text})[0]; + } + + private static class DefaultPolicy extends ComparisonPolicy { + public DefaultPolicy() { + super(CommonBundle.message("comparison.policy.default.name")); + } + + @NotNull @Override - protected Object[] getWrappers(String[] strings) { + protected Object[] getWrappers(@NotNull DiffString[] strings) { return strings; } + @NotNull @Override - protected Object[] getLineWrappers(String[] lines) { + protected Object[] getLineWrappers(@NotNull DiffString[] lines) { return lines; } + @NotNull @Override - public DiffFragment createFragment(Word word1, Word word2) { + public DiffFragment createFragment(@NotNull Word word1, @NotNull Word word2) { return createFragment(word1.getText(), word2.getText()); } @@ -71,18 +119,24 @@ public abstract class ComparisonPolicy { public String toString() { return "DEFAULT"; } - }; + } + + private static class TrimSpacePolicy extends ComparisonPolicy { + public TrimSpacePolicy() { + super(CommonBundle.message("comparison.policy.trim.space.name")); + } - public static final ComparisonPolicy TRIM_SPACE = new ComparisonPolicy(CommonBundle.message("comparison.policy.trim.space.name")) { + @NotNull @Override - protected Object[] getLineWrappers(String[] lines) { + protected Object[] getLineWrappers(@NotNull DiffString[] lines) { return trimStrings(lines); } + @NotNull @Override - public DiffFragment createFragment(Word word1, Word word2) { - String text1 = word1.getText(); - String text2 = word2.getText(); + public DiffFragment createFragment(@NotNull Word word1, @NotNull Word word2) { + DiffString text1 = word1.getText(); + DiffString text2 = word2.getText(); if (word1.isWhitespace() && word2.isWhitespace() && word1.atEndOfLine() && word2.atEndOfLine()) { return DiffFragment.unchanged(text1, text2); @@ -90,16 +144,17 @@ public abstract class ComparisonPolicy { return createFragment(text1, text2); } + @NotNull @Override - protected Object[] getWrappers(String[] strings) { + protected Object[] getWrappers(@NotNull DiffString[] strings) { Object[] result = new Object[strings.length]; boolean atBeginning = true; for (int i = 0; i < strings.length; i++) { - String string = strings[i]; - String wrapper = atBeginning ? StringUtil.trimLeading(string) : string; - if (StringUtil.endsWithChar(wrapper, '\n')) { + DiffString string = strings[i]; + DiffString wrapper = atBeginning ? string.trimLeading() : string; + if (wrapper.endsWith('\n')) { atBeginning = true; - wrapper = StringUtil.trimTrailing(wrapper); + wrapper = wrapper.trimTrailing(); } else { atBeginning = false; @@ -109,128 +164,66 @@ public abstract class ComparisonPolicy { return result; } - - @SuppressWarnings({"HardCodedStringLiteral"}) public String toString() { return "TRIM"; } - }; - - public static final ComparisonPolicy IGNORE_SPACE = new IgnoreSpacePolicy(); - - private static String toNotNull(String text) { - return text == null ? "" : text; } - protected abstract Object[] getWrappers(String[] strings); - - protected abstract Object[] getLineWrappers(String[] lines); - - protected Object[] trimStrings(String[] strings) { - Object[] result = new Object[strings.length]; - for (int i = 0; i < strings.length; i++) { - String string = strings[i]; - result[i] = string.trim(); - } - return result; - } - - public DiffFragment createFragment(String text1, String text2) { - text1 = toNull(text1); - text2 = toNull(text2); - if (text1 == null && text2 == null) return new DiffFragment("", ""); - DiffFragment result = new DiffFragment(text1, text2); - if (text1 != null && text2 != null) { - result.setModified(!getWrapper(text1).equals(getWrapper(text2))); - } - return result; - } - - private String toNull(String text1) { - return text1 == null || text1.isEmpty() ? null : text1; - } - - private Object getWrapper(String text) { - return getWrappers(new String[]{text})[0]; - } - - public boolean isEqual(DiffFragment fragment) { - if (fragment.isOneSide()) return false; - Object[] wrappers = getLineWrappers(new String[]{fragment.getText1(), fragment.getText2()}); - return Comparing.equal(wrappers[0], wrappers[1]); - } - - public Word createFormatting(String text, TextRange textRange) { - return new Formatting(text, textRange); - } - - public abstract DiffFragment createFragment(Word word1, Word word2); - - public String getName() { - return myName; - } - - public static final ComparisonPolicy[] COMPARISON_POLICIES = new ComparisonPolicy[]{DEFAULT, IGNORE_SPACE, TRIM_SPACE}; - - public static ComparisonPolicy[] getAllInstances() { - return COMPARISON_POLICIES; - } - - private static class IgnoreSpacePolicy extends ComparisonPolicy implements DiffCorrection.FragmentProcessor<DiffCorrection.FragmentsCollector> { + private static class IgnoreSpacePolicy extends ComparisonPolicy + implements DiffCorrection.FragmentProcessor<DiffCorrection.FragmentsCollector> { public IgnoreSpacePolicy() { super(CommonBundle.message("comparison.policy.ignore.spaces.name")); } + @NotNull @Override - protected Object[] getLineWrappers(String[] lines) { + protected Object[] getLineWrappers(@NotNull DiffString[] lines) { Object[] result = new Object[lines.length]; for (int i = 0; i < lines.length; i++) { - String line = lines[i]; + DiffString line = lines[i]; result[i] = getWrapper(line); } return result; } + @NotNull @Override - public DiffFragment[] buildFragments(String[] strings1, String[] strings2) throws FilesTooBigForDiffException { + public DiffFragment[] buildFragments(@NotNull DiffString[] strings1, @NotNull DiffString[] strings2) + throws FilesTooBigForDiffException { DiffFragment[] fragments = super.buildFragments(strings1, strings2); DiffCorrection.FragmentsCollector collector = new DiffCorrection.FragmentsCollector(); collector.processAll(fragments, this); return collector.toArray(); } - private Object getWrapper(String line) { - StringBuilder builder = new StringBuilder(line.length()); - for (int i = 0; i < line.length(); i++) { - char aChar = line.charAt(i); - if (StringUtil.isWhiteSpace(aChar)) continue; - builder.append(aChar); - } - return builder.toString(); + @NotNull + private static Object getWrapper(@NotNull DiffString line) { + return line.skipSpaces(); } + @NotNull @Override - public DiffFragment createFragment(Word word1, Word word2) { - String text1 = word1.getText(); - String text2 = word2.getText(); - return word1.isWhitespace() && word2.isWhitespace() ? - DiffFragment.unchanged(text1, text2) : - createFragment(text1, text2); + public DiffFragment createFragment(@NotNull Word word1, @NotNull Word word2) { + DiffString text1 = word1.getText(); + DiffString text2 = word2.getText(); + return word1.isWhitespace() && word2.isWhitespace() ? DiffFragment.unchanged(text1, text2) : createFragment(text1, text2); } + @NotNull @Override - public DiffFragment createFragment(String text1, String text2) { - String toCompare1 = toNotNull(text1); - String toCompare2 = toNotNull(text2); + public DiffFragment createFragment(DiffString text1, DiffString text2) { + DiffString toCompare1 = toNotNull(text1); + DiffString toCompare2 = toNotNull(text2); if (getWrapper(toCompare1).equals(getWrapper(toCompare2))) { return DiffFragment.unchanged(toCompare1, toCompare2); } return new DiffFragment(text1, text2); } + @NotNull @Override - protected Object[] getWrappers(String[] strings) { + protected Object[] getWrappers(@NotNull DiffString[] strings) { return trimStrings(strings); } @@ -240,21 +233,76 @@ public abstract class ComparisonPolicy { } @Override - public void process(DiffFragment fragment, DiffCorrection.FragmentsCollector collector) { + public void process(@NotNull DiffFragment fragment, @NotNull DiffCorrection.FragmentsCollector collector) { if (fragment.isEqual()) { collector.add(fragment); return; } if (fragment.isOneSide()) { FragmentSide side = FragmentSide.chooseSide(fragment); - String text = side.getText(fragment); - String trimed = text.trim(); + DiffString text = side.getText(fragment); + DiffString trimed = text.trim(); if (trimed.isEmpty()) { - collector.add(side.createFragment(text, "", false)); + collector.add(side.createFragment(text, DiffString.EMPTY, false)); return; } } collector.add(fragment); } } + + @Nullable + private static DiffString toNull(@Nullable DiffString text1) { + return text1 == null || text1.isEmpty() ? null : text1; + } + + @NotNull + private static DiffString toNotNull(@Nullable DiffString text) { + return text == null ? DiffString.EMPTY : text; + } + + @NotNull + protected Object[] trimStrings(@NotNull DiffString[] strings) { + Object[] result = new Object[strings.length]; + for (int i = 0; i < strings.length; i++) { + DiffString string = strings[i]; + result[i] = string.trim(); + } + return result; + } + + public boolean isEqual(@NotNull DiffFragment fragment) { + if (fragment.isOneSide()) return false; + Object[] wrappers = getLineWrappers(new DiffString[]{fragment.getText1(), fragment.getText2()}); + return Comparing.equal(wrappers[0], wrappers[1]); + } + + @NotNull + public Word createFormatting(@NotNull DiffString text, @NotNull TextRange textRange) { + return new Formatting(text, textRange); + } + + public static ComparisonPolicy[] getAllInstances() { + return COMPARISON_POLICIES; + } + + @NotNull + @TestOnly + protected Object[] getWrappers(@NotNull String[] lines) { + DiffString[] unsafeStrings = new DiffString[lines.length]; + for (int i = 0; i < lines.length; i++) { + unsafeStrings[i] = DiffString.createNullable(lines[i]); + } + return getWrappers(unsafeStrings); + } + + @NotNull + @TestOnly + protected Object[] getLineWrappers(@NotNull String[] lines) { + DiffString[] unsafeStrings = new DiffString[lines.length]; + for (int i = 0; i < lines.length; i++) { + unsafeStrings[i] = DiffString.createNullable(lines[i]); + } + return getLineWrappers(unsafeStrings); + } } diff --git a/platform/util/src/com/intellij/openapi/diff/impl/DiffFragmentBuilder.java b/platform/util/src/com/intellij/openapi/diff/impl/DiffFragmentBuilder.java index 3b6a00b16fb9..64630e981753 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/DiffFragmentBuilder.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/DiffFragmentBuilder.java @@ -21,9 +21,12 @@ package com.intellij.openapi.diff.impl; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.util.TextRange; import com.intellij.util.diff.Diff; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.LinkedList; import java.util.List; @@ -56,25 +59,26 @@ public class DiffFragmentBuilder { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.DiffFragmentBuilder"); - private final String[] mySource1; - private final String[] mySource2; + @NotNull private final DiffString[] mySource1; + @NotNull private final DiffString[] mySource2; private int myLastLine1 = 1; private int myLastLine2 = 1; - private final List<DiffFragment> myData = new LinkedList<DiffFragment>(); + @NotNull private final List<DiffFragment> myData = new LinkedList<DiffFragment>(); - public DiffFragmentBuilder(String[] source1, String[] source2) { + public DiffFragmentBuilder(@NotNull DiffString[] source1, @NotNull DiffString[] source2) { mySource1 = source1; mySource2 = source2; init(); } + @NotNull private List<DiffFragment> getFragments() { return myData; } private void finish() { - String text1 = null; - String text2 = null; + DiffString text1 = null; + DiffString text2 = null; if (myLastLine1 <= mySource1.length) { text1 = concatenate(mySource1, myLastLine1, mySource1.length); } @@ -91,10 +95,10 @@ public class DiffFragmentBuilder { myLastLine1 = myLastLine2 = 1; } - private void append(int line, TextRange range) { + private void append(int line, @NotNull TextRange range) { LOG.debug("DiffFragmentBuilder.append(" + line + "," + range + "), modified:"); - String text1 = null; - String text2 = null; + DiffString text1 = null; + DiffString text2 = null; int start = range.getStartOffset(); int end = range.getEndOffset(); if (myLastLine1 <= line) { @@ -111,10 +115,10 @@ public class DiffFragmentBuilder { myLastLine2 = end + 1; } - private void change(TextRange range1, TextRange range2) { + private void change(@NotNull TextRange range1, @NotNull TextRange range2) { LOG.debug("DiffFragmentBuilder.change(" + range1 + "," + range2 + ")"); - String text1 = null, text2 = null; + DiffString text1 = null, text2 = null; int start1 = range1.getStartOffset(); int end1 = range1.getEndOffset(); int start2 = range2.getStartOffset(); @@ -134,11 +138,11 @@ public class DiffFragmentBuilder { myLastLine2 = end2 + 1; } - private void delete(TextRange range, int line) { + private void delete(@NotNull TextRange range, int line) { LOG.debug("DiffFragmentBuilder.delete(" + range + "," + line + ")"); - String text1 = null; - String text2 = null; + DiffString text1 = null; + DiffString text2 = null; int start = range.getStartOffset(); int end = range.getEndOffset(); if (myLastLine1 < start) { @@ -155,15 +159,13 @@ public class DiffFragmentBuilder { myLastLine2 = line + 1; } - private static String concatenate(String[] strings, int start, int end) { - int len = 0; - for (int i = start - 1; i < end; i++) len += strings[i] == null ? 0 : strings[i].length(); - StringBuilder buffer = new StringBuilder(len); - for (int i = start - 1; i < end; i++) buffer.append(strings[i]); - return buffer.toString(); + @NotNull + private static DiffString concatenate(@NotNull DiffString[] strings, int start, int end) { + return DiffString.concatenate(strings, start - 1, end - start + 1); } - public DiffFragment[] buildFragments(Diff.Change change) { + @NotNull + public DiffFragment[] buildFragments(@Nullable Diff.Change change) { while (change != null) { if (change.inserted > 0 && change.deleted > 0) { change( diff --git a/platform/util/src/com/intellij/openapi/diff/impl/fragments/LineFragment.java b/platform/util/src/com/intellij/openapi/diff/impl/fragments/LineFragment.java index 705be4f7ad1e..57399b5b4220 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/fragments/LineFragment.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/fragments/LineFragment.java @@ -16,10 +16,12 @@ package com.intellij.openapi.diff.impl.fragments; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.util.TextDiffTypeEnum; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -147,9 +149,10 @@ public class LineFragment extends LineBlock implements Fragment { return myChildren == null || myChildren.isEmpty() ? null : myChildren.iterator(); } - public String getText(String text, FragmentSide side) { + @NotNull + public DiffString getText(@NotNull DiffString text, @NotNull FragmentSide side) { TextRange range = getRange(side); - return range.substring(text); + return text.substring(range.getStartOffset(), range.getEndOffset()); } @@ -186,7 +189,7 @@ public class LineFragment extends LineBlock implements Fragment { } boolean hasLineChildren = false; boolean hasInlineChildren = false; - for (; iterator.hasNext();) { + while(iterator.hasNext()) { Fragment fragment = iterator.next(); boolean lineChild = fragment instanceof LineFragment; hasLineChildren |= lineChild; diff --git a/platform/util/src/com/intellij/openapi/diff/impl/highlighting/FragmentSide.java b/platform/util/src/com/intellij/openapi/diff/impl/highlighting/FragmentSide.java index 620a8f3e0f55..efdf58937db5 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/highlighting/FragmentSide.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/highlighting/FragmentSide.java @@ -16,19 +16,23 @@ package com.intellij.openapi.diff.impl.highlighting; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public enum FragmentSide { SIDE1(0, 0) { @Override - public String getText(DiffFragment fragment) { + @Nullable + public DiffString getText(@NotNull DiffFragment fragment) { return fragment.getText1(); } @Override - protected DiffFragment createDiffFragment(String text, String otherText) { + @NotNull + protected DiffFragment createDiffFragment(@Nullable DiffString text, @Nullable DiffString otherText) { return new DiffFragment(text, otherText); } @@ -40,12 +44,14 @@ public enum FragmentSide { SIDE2(1, 2) { @Override - public String getText(DiffFragment fragment) { + @Nullable + public DiffString getText(@NotNull DiffFragment fragment) { return fragment.getText2(); } @Override - protected DiffFragment createDiffFragment(String text, String otherText) { + @NotNull + protected DiffFragment createDiffFragment(@Nullable DiffString text, @Nullable DiffString otherText) { return new DiffFragment(otherText, text); } @@ -65,15 +71,18 @@ public enum FragmentSide { myMergeIndex = mergeIndex; } - public DiffFragment createFragment(String text, String otherText, boolean modified) { + @NotNull + public DiffFragment createFragment(@Nullable DiffString text, @Nullable DiffString otherText, boolean modified) { DiffFragment fragment = createDiffFragment(text, otherText); if (!fragment.isOneSide()) fragment.setModified(modified); return fragment; } - public abstract String getText(DiffFragment fragment); + @Nullable + public abstract DiffString getText(@NotNull DiffFragment fragment); public abstract FragmentSide otherSide(); - protected abstract DiffFragment createDiffFragment(String text, String otherText); + @NotNull + protected abstract DiffFragment createDiffFragment(@Nullable DiffString text, @Nullable DiffString otherText); public int getIndex() { return myIndex; @@ -83,7 +92,8 @@ public enum FragmentSide { return myMergeIndex; } - public String getOtherText(DiffFragment fragment) { + @Nullable + public DiffString getOtherText(@NotNull DiffFragment fragment) { return otherSide().getText(fragment); } diff --git a/platform/util/src/com/intellij/openapi/diff/impl/highlighting/Util.java b/platform/util/src/com/intellij/openapi/diff/impl/highlighting/Util.java index 83cfa988c573..15c24d364118 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/highlighting/Util.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/highlighting/Util.java @@ -16,11 +16,14 @@ package com.intellij.openapi.diff.impl.highlighting; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.diff.Diff; import gnu.trove.TIntHashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Arrays; @@ -33,14 +36,15 @@ public class Util { public static final TIntHashSet DELIMITERS_SET = new TIntHashSet(); static { - char[] delimiters = Util.DELIMITERS.toCharArray(); + char[] delimiters = DELIMITERS.toCharArray(); for (int i = 0; i < delimiters.length; i++) { char delimiter = delimiters[i]; - Util.DELIMITERS_SET.add(delimiter); + DELIMITERS_SET.add(delimiter); } } - static String[] splitByWord(String string) { + @NotNull + static String[] splitByWord(@NotNull String string) { BufferedStringList stringList = new BufferedStringList(); StringTokenizer tokenizer = new StringTokenizer(string, DELIMITERS, true); while (tokenizer.hasMoreTokens()) { @@ -62,19 +66,19 @@ public class Util { return stringList.toArray(); } - static boolean isSpaceOnly(DiffFragment fragment) { + static boolean isSpaceOnly(@NotNull DiffFragment fragment) { return isSpaceOnly(fragment.getText1()) && isSpaceOnly(fragment.getText2()); } - private static boolean isSpaceOnly(String string) { + private static boolean isSpaceOnly(@Nullable DiffString string) { if (string == null) return true; - for (int i = 0; i < string.length(); i++) if (!Character.isWhitespace(string.charAt(i))) return false; - return true; + return string.isEmptyOrSpaces(); } - static DiffFragment[] splitByLines(DiffFragment fragment) { - String[] lines1 = splitByLines(fragment.getText1()); - String[] lines2 = splitByLines(fragment.getText2()); + @NotNull + static DiffFragment[] splitByLines(@NotNull DiffFragment fragment) { + DiffString[] lines1 = splitByLines(fragment.getText1()); + DiffString[] lines2 = splitByLines(fragment.getText2()); if (lines1 != null && lines2 != null && lines1.length != lines2.length) { LOG.error("1:<" + fragment.getText1() + "> 2:<" + fragment.getText2() + ">"); } @@ -86,22 +90,16 @@ public class Util { return lines; } - private static String[] splitByLines(String string) { + @Nullable + private static DiffString[] splitByLines(@Nullable DiffString string) { if (string == null) return null; - if (string.indexOf('\n') == -1) return new String[]{string}; - String[] strings = string.split("\n", -1); - for (int i = 0; i < strings.length - 1; i++) { - strings[i] += "\n"; - } - if (StringUtil.endsWithChar(string, '\n')) { - String[] result = new String[strings.length - 1]; - System.arraycopy(strings, 0, result, 0, strings.length - 1); - return result; - } - return strings; + if (string.indexOf('\n') == -1) return new DiffString[]{string}; + + return string.tokenize(); } - public static DiffFragment[][] splitByUnchangedLines(DiffFragment[] fragments) { + @NotNull + public static DiffFragment[][] splitByUnchangedLines(@NotNull DiffFragment[] fragments) { List2D result = new List2D(); for (int i = 0; i < fragments.length; i++) { DiffFragment fragment = fragments[i]; @@ -109,8 +107,10 @@ public class Util { result.add(fragment); continue; } - String text1 = fragment.getText1(); - String text2 = fragment.getText2(); + DiffString text1 = fragment.getText1(); + DiffString text2 = fragment.getText2(); + assert text1 != null; + assert text2 != null; if (StringUtil.endsWithChar(text1, '\n') && StringUtil.endsWithChar(text2, '\n')) { result.add(fragment); result.newRow(); @@ -139,7 +139,7 @@ public class Util { return result.toArray(); } - public static Diff.Change concatEquals(Diff.Change change, Object[] left, Object[] right) { + public static Diff.Change concatEquals(Diff.Change change, @NotNull Object[] left, @NotNull Object[] right) { MyChange startChange = new MyChange(0, 0, 0, 0); MyChange lastChange = startChange; while (change != null) { @@ -187,7 +187,7 @@ public class Util { return startChange.link; } - static int calcShift(Object[] list, int limit, int start, int length) { + static int calcShift(@NotNull Object[] list, int limit, int start, int length) { int shift = start - limit; for (int i = 0; i < shift; i++) { if (!list[limit + i].equals(list[start + length - shift + i])) return 0; @@ -195,20 +195,22 @@ public class Util { return -shift; } - public static DiffFragment unite(DiffFragment fragment1, DiffFragment fragment2) { + @NotNull + public static DiffFragment unite(@NotNull DiffFragment fragment1, @NotNull DiffFragment fragment2) { LOG.assertTrue(isSameType(fragment1, fragment2)); if (!fragment1.isOneSide()) { - String unitedText1 = fragment1.getText1() + fragment2.getText1(); - String unitedText2 = fragment1.getText2() + fragment2.getText2(); + DiffString unitedText1 = DiffString.concatenateNullable(fragment1.getText1(), fragment2.getText1()); + DiffString unitedText2 = DiffString.concatenateNullable(fragment1.getText2(), fragment2.getText2()); LOG.assertTrue(fragment1.isEqual() == fragment2.isEqual()); return fragment1.isEqual() ? DiffFragment.unchanged(unitedText1, unitedText2) : new DiffFragment(unitedText1, unitedText2); } FragmentSide side = FragmentSide.chooseSide(fragment1); - return side.createFragment(side.getText(fragment1) + side.getText(fragment2), null, fragment1.isModified()); + return side + .createFragment(DiffString.concatenateNullable(side.getText(fragment1), side.getText(fragment2)), null, fragment1.isModified()); } - public static boolean isSameType(DiffFragment fragment1, DiffFragment fragment2) { + public static boolean isSameType(@NotNull DiffFragment fragment1, @NotNull DiffFragment fragment2) { if (fragment1.isEqual()) return fragment2.isEqual(); if (fragment1.isChange()) return fragment2.isChange(); if (fragment1.getText1() == null) return fragment2.getText1() == null; @@ -217,52 +219,46 @@ public class Util { return false; } - public static String getText(DiffFragment[] fragments, FragmentSide side) { - StringBuffer buffer = new StringBuffer(); + @NotNull + public static DiffString getText(@NotNull DiffFragment[] fragments, @NotNull FragmentSide side) { + DiffString[] data = new DiffString[fragments.length]; for (int i = 0; i < fragments.length; i++) { DiffFragment fragment = fragments[i]; - String text = side.getText(fragment); - if (text != null) buffer.append(text); + data[i] = side.getText(fragment); } - return buffer.toString(); + return DiffString.concatenate(data); } - public static DiffFragment concatenate(DiffFragment[] line) { + @NotNull + public static DiffFragment concatenate(@NotNull DiffFragment[] line) { return concatenate(line, 0, line.length); } - public static DiffFragment concatenate(DiffFragment[] line, int from, int to) { - String[] data1 = new String[to - from]; - String[] data2 = new String[to - from]; + @NotNull + public static DiffFragment concatenate(@NotNull DiffFragment[] line, int from, int to) { + DiffString[] data1 = new DiffString[to - from]; + DiffString[] data2 = new DiffString[to - from]; - int len1 = 0; - int len2 = 0; boolean isEqual = true; for (int i = 0; i < to - from; i++) { - isEqual &= line[i + from].isEqual(); - data1[i] = line[i + from].getText1(); - data2[i] = line[i + from].getText2(); - len1 += data1[i] == null ? 0 : data1[i].length(); - len2 += data2[i] == null ? 0 : data2[i].length(); - } - - StringBuilder buffer1 = new StringBuilder(len1); - StringBuilder buffer2 = new StringBuilder(len2); - for (int i = 0; i < to - from; i++) { - if (data1[i] != null) buffer1.append(data1[i]); - if (data2[i] != null) buffer2.append(data2[i]); + DiffFragment fragment = line[from + i]; + isEqual &= fragment.isEqual(); + data1[i] = fragment.getText1(); + data2[i] = fragment.getText2(); } - String text1 = notEmptyContent(buffer1); - String text2 = notEmptyContent(buffer2); + DiffString text1 = notEmptyContent(DiffString.concatenate(data1)); + DiffString text2 = notEmptyContent(DiffString.concatenate(data2)); return isEqual ? DiffFragment.unchanged(text1, text2) : new DiffFragment(text1, text2); } - private static String notEmptyContent(StringBuilder buffer) { - return buffer.length() > 0 ? buffer.toString() : null; + @Nullable + private static DiffString notEmptyContent(@NotNull DiffString string) { + return string.length() > 0 ? string : null; } - public static DiffFragment[][] uniteFormattingOnly(DiffFragment[][] lines) { + @NotNull + public static DiffFragment[][] uniteFormattingOnly(@NotNull DiffFragment[][] lines) { List2D result = new List2D(); for (int i = 0; i < lines.length; i++) { DiffFragment[] line = lines[i]; @@ -276,20 +272,20 @@ public class Util { return result.toArray(); } - private static boolean areEqualOrFormatting(DiffFragment[] fragments) { + private static boolean areEqualOrFormatting(@NotNull DiffFragment[] fragments) { for (int i = 0; i < fragments.length; i++) { DiffFragment fragment = fragments[i]; if (fragment.isEqual()) continue; for (int side = 0; side < 2; side++) { - String text = FragmentSide.fromIndex(side).getText(fragment); - if (text == null || text.trim().isEmpty()) continue; + DiffString text = FragmentSide.fromIndex(side).getText(fragment); + if (text == null || text.isEmptyOrSpaces()) continue; return false; } } return true; } - private static boolean areEqual(DiffFragment[] fragments) { + private static boolean areEqual(@NotNull DiffFragment[] fragments) { for (int i = 0; i < fragments.length; i++) { DiffFragment fragment = fragments[i]; if (!fragment.isEqual()) return false; @@ -297,7 +293,8 @@ public class Util { return true; } - public static DiffFragment[] cutFirst(DiffFragment[] fragments) { + @NotNull + public static DiffFragment[] cutFirst(@NotNull DiffFragment[] fragments) { fragments = transformHeadInsert(fragments, FragmentSide.SIDE1); fragments = transformHeadInsert(fragments, FragmentSide.SIDE2); @@ -307,10 +304,10 @@ public class Util { for (int i = 0; i < fragments.length; i++) { DiffFragment fragment = fragments[i]; if (fragment == null) continue; - String text = side.getText(fragment); + DiffString text = side.getText(fragment); if (text == null || text.isEmpty()) continue; text = text.length() > 1 ? text.substring(1) : null; - String otherText = side.getOtherText(fragment); + DiffString otherText = side.getOtherText(fragment); if (otherText == null && text == null) { fragments[i] = null; nullCount++; @@ -330,7 +327,8 @@ public class Util { return result; } - private static DiffFragment[] transformHeadInsert(DiffFragment[] fragments, FragmentSide side) { + @NotNull + private static DiffFragment[] transformHeadInsert(@NotNull DiffFragment[] fragments, @NotNull FragmentSide side) { // transforms {abc}abcd into a{bca}bcd if (fragments.length >= 2) { DiffFragment first = fragments[0]; @@ -341,15 +339,15 @@ public class Util { if (side.getText(first) != null) { return fragments; } - String rightText = side.getOtherText(first); - String secondText = side.getText(second); + DiffString rightText = side.getOtherText(first); + DiffString secondText = side.getText(second); if (!Comparing.equal(side.getOtherText(second), secondText)) { return fragments; } if (secondText.charAt(0) == rightText.charAt(0)) { List<DiffFragment> result = new ArrayList<DiffFragment>(); result.add(side.createFragment(rightText.substring(0, 1), rightText.substring(0, 1), false)); - result.add(side.createFragment(null, rightText.substring(1) + secondText.substring(0, 1), true)); + result.add(side.createFragment(null, DiffString.concatenate(rightText.substring(1), secondText.substring(0, 1)), true)); result.add(side.createFragment(secondText.substring(1), secondText.substring(1), second.isModified())); result.addAll(Arrays.asList(fragments).subList(2, fragments.length)); return result.toArray(new DiffFragment[result.size()]); @@ -363,11 +361,11 @@ public class Util { super(line0, line1, deleted, inserted, null); } - public MyChange copyNext(Diff.Change change) { + public MyChange copyNext(@NotNull Diff.Change change) { return copyNext(change, 0); } - public MyChange copyNext(Diff.Change change, int shift) { + public MyChange copyNext(@NotNull Diff.Change change, int shift) { MyChange result = new MyChange(change.line0 + shift, change.line1 + shift, change.deleted, change.inserted); setNext(result); return result; diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/ByWord.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/ByWord.java index 21740dc83a67..9aa43f5f1708 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/ByWord.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/ByWord.java @@ -20,13 +20,16 @@ import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.Util; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.util.TextRange; import com.intellij.util.diff.Diff; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; import java.util.ArrayList; -public class ByWord implements DiffPolicy{ +public class ByWord implements DiffPolicy { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.ByWord"); private final ComparisonPolicy myComparisonPolicy; @@ -34,8 +37,15 @@ public class ByWord implements DiffPolicy{ myComparisonPolicy = comparisonPolicy; } + @NotNull + @TestOnly + public DiffFragment[] buildFragments(@NotNull String text1, @NotNull String text2) throws FilesTooBigForDiffException { + return buildFragments(DiffString.create(text1), DiffString.create(text2)); + } + + @NotNull @Override - public DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException { + public DiffFragment[] buildFragments(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException { Word[] words1 = buildWords(text1, myComparisonPolicy); Word[] words2 = buildWords(text2, myComparisonPolicy); Diff.Change change = Diff.buildChanges(words1, words2); @@ -54,8 +64,8 @@ public class ByWord implements DiffPolicy{ } else if (change.deleted == 0) { processOneside(version2, change.inserted); } else { - String prefix1 = version1.getCurrentWordPrefix(); - String prefix2 = version2.getCurrentWordPrefix(); + DiffString prefix1 = version1.getCurrentWordPrefix(); + DiffString prefix2 = version2.getCurrentWordPrefix(); if (!prefix1.isEmpty() || !prefix2.isEmpty()) result.add(myComparisonPolicy.createFragment(prefix1, prefix2)); result.addChangedWords(change.deleted, change.inserted); @@ -66,7 +76,7 @@ public class ByWord implements DiffPolicy{ result.addTails(); DiffFragment[] fragments = result.getFragments(); DiffFragment firstFragment = fragments[0]; - if (DiffFragment.isEmpty(firstFragment)) { + if (firstFragment.isEmpty()) { DiffFragment[] newFragments = new DiffFragment[fragments.length - 1]; System.arraycopy(fragments, 1, newFragments, 0, newFragments.length); fragments = newFragments; @@ -74,7 +84,7 @@ public class ByWord implements DiffPolicy{ return fragments; } - private int countNotWhitespaces(Word[] words) { + private static int countNotWhitespaces(@NotNull Word[] words) { int counter = 0; for (int i = 0; i < words.length; i++) { Word word = words[i]; @@ -83,7 +93,7 @@ public class ByWord implements DiffPolicy{ return counter; } - private int countEqual(Diff.Change change, Word[] words1, Word[] words2) { + private static int countEqual(Diff.Change change, @NotNull Word[] words1, @NotNull Word[] words2) { int counter = 0; int position1 = 0; int position2 = 0; @@ -111,19 +121,26 @@ public class ByWord implements DiffPolicy{ return counter; } - private void processOneside(FragmentBuilder.Version version, int wordCount) { - String prefix = version.getCurrentWordPrefix(); + private static void processOneside(@NotNull FragmentBuilder.Version version, int wordCount) { + DiffString prefix = version.getCurrentWordPrefix(); version.addOneSide(prefix, wordCount); } - private void processEquals(int changed1, int changed2, FragmentBuilder result) throws FilesTooBigForDiffException { + private static void processEquals(int changed1, int changed2, @NotNull FragmentBuilder result) throws FilesTooBigForDiffException { while (result.getVersion1().getCurrentWordIndex() < changed1) { result.processEqual(); } LOG.assertTrue(changed2 == result.getVersion2().getCurrentWordIndex()); } - static Word[] buildWords(String text, ComparisonPolicy policy) { + @NotNull + @TestOnly + static Word[] buildWords(@NotNull String text, @NotNull ComparisonPolicy policy) { + return buildWords(DiffString.create(text), policy); + } + + @NotNull + static Word[] buildWords(@NotNull DiffString text, @NotNull ComparisonPolicy policy) { ArrayList<Word> words = new ArrayList<Word>(); if (text.isEmpty() || !Character.isWhitespace(text.charAt(0))) words.add(policy.createFormatting(text, TextRange.EMPTY_RANGE)); @@ -167,7 +184,7 @@ public class ByWord implements DiffPolicy{ private final DiffCorrection.ChangedSpace CORRECTION; private final ComparisonPolicy myComparisonPolicy; - public FragmentBuilder(Word[] words1, Word[] words2, ComparisonPolicy comparisonPolicy, String text1, String text2) { + public FragmentBuilder(@NotNull Word[] words1, @NotNull Word[] words2, @NotNull ComparisonPolicy comparisonPolicy, @NotNull DiffString text1, @NotNull DiffString text2) { myVersion1 = new Version(words1, text1, this, true); myVersion2 = new Version(words2, text2, this, false); BY_CHAR = new ByChar(comparisonPolicy); @@ -175,24 +192,27 @@ public class ByWord implements DiffPolicy{ myComparisonPolicy = comparisonPolicy; } + @NotNull public DiffFragment[] getFragments() { return myFragments.toArray(new DiffFragment[myFragments.size()]); } + @NotNull public Version getVersion1() { return myVersion1; } + @NotNull public Version getVersion2() { return myVersion2; } - private void addAll(DiffFragment[] fragments) { + private void addAll(@NotNull DiffFragment[] fragments) { for (int i = 0; i < fragments.length; i++) { DiffFragment fragment = fragments[i]; add(fragment); } } - private void add(DiffFragment fragment) { - String text1 = fragment.getText1(); - String text2 = fragment.getText2(); + private void add(@NotNull DiffFragment fragment) { + DiffString text1 = fragment.getText1(); + DiffString text2 = fragment.getText2(); if (text1 != null) myVersion1.addOffset(text1.length()); if (text2 != null) myVersion2.addOffset(text2.length()); if (fragment.isEqual() && !myFragments.isEmpty()) { @@ -207,7 +227,7 @@ public class ByWord implements DiffPolicy{ myFragments.add(fragment); } - private void addEqual(Word word1, Word word2) throws FilesTooBigForDiffException { + private void addEqual(@NotNull Word word1, @NotNull Word word2) throws FilesTooBigForDiffException { addAll(CORRECTION.correct(new DiffFragment[]{myComparisonPolicy.createFragment(word1, word2)})); } @@ -221,19 +241,20 @@ public class ByWord implements DiffPolicy{ myVersion2.incCurrentWord(); } - private DiffFragment[] fragmentsByChar(String text1, String text2) throws FilesTooBigForDiffException { + @NotNull + private DiffFragment[] fragmentsByChar(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException { if (text1.isEmpty() && text2.isEmpty()) { return DiffFragment.EMPTY_ARRAY; } - final String side1 = myVersion1.getPrevChar() + text1; - final String side2 = myVersion2.getPrevChar() + text2; + final DiffString side1 = text1.preappend(myVersion1.getPrevChar()); + final DiffString side2 = text2.preappend(myVersion2.getPrevChar()); DiffFragment[] fragments = BY_CHAR.buildFragments(side1, side2); return Util.cutFirst(fragments); } private void addPostfixes() throws FilesTooBigForDiffException { - String postfix1 = myVersion1.getCurrentWordPostfixAndOneMore(); - String postfix2 = myVersion2.getCurrentWordPostfixAndOneMore(); + DiffString postfix1 = myVersion1.getCurrentWordPostfixAndOneMore(); + DiffString postfix2 = myVersion2.getCurrentWordPostfixAndOneMore(); int length1 = postfix1.length(); int length2 = postfix2.length(); DiffFragment wholePostfix = myComparisonPolicy.createFragment(postfix1, postfix2); @@ -245,20 +266,23 @@ public class ByWord implements DiffPolicy{ DiffFragment[] fragments = BY_CHAR.buildFragments(postfix1, postfix2); DiffFragment firstFragment = fragments[0]; if (firstFragment.isEqual()) { - final String text1 = cutLast(firstFragment.getText1(), length1); - final String text2 = cutLast(firstFragment.getText2(), length2); + final DiffString text1 = cutLast(firstFragment.getText1(), length1); + final DiffString text2 = cutLast(firstFragment.getText2(), length2); add(myComparisonPolicy.createFragment(text1, text2)); //add(firstFragment); } } } - private String cutLast(String text, int length) { + @NotNull + private static DiffString cutLast(@NotNull DiffString text, int length) { if (text.length() < length) return text; - else return text.substring(0, text.length() - 1); + else { + return text.substring(0, text.length() - 1); + } } - private void addOneSide(String text, FragmentSide side) { + private void addOneSide(@NotNull DiffString text, @NotNull FragmentSide side) { DiffFragment fragment = side.createFragment(text, null, false); add(myComparisonPolicy.createFragment(fragment.getText1(), fragment.getText2())); } @@ -270,8 +294,8 @@ public class ByWord implements DiffPolicy{ } public void addTails() throws FilesTooBigForDiffException { - String tail1 = myVersion1.getNotProcessedTail(); - String tail2 = myVersion2.getNotProcessedTail(); + DiffString tail1 = myVersion1.getNotProcessedTail(); + DiffString tail2 = myVersion2.getNotProcessedTail(); if (tail1.isEmpty() && tail2.isEmpty()) return; DiffFragment[] fragments = fragmentsByChar(tail1, tail2); if (!myFragments.isEmpty()) { @@ -301,14 +325,14 @@ public class ByWord implements DiffPolicy{ } public static class Version { - private final Word[] myWords; + @NotNull private final Word[] myWords; private int myCurrentWord = 0; private int myOffset = 0; - private final String myText; - private final FragmentBuilder myBuilder; + @NotNull private final DiffString myText; + @NotNull private final FragmentBuilder myBuilder; private final FragmentSide mySide; - public Version(Word[] words, String text, FragmentBuilder builder, boolean delete) { + public Version(@NotNull Word[] words, @NotNull DiffString text, @NotNull FragmentBuilder builder, boolean delete) { myWords = words; myText = text; myBuilder = builder; @@ -331,7 +355,8 @@ public class ByWord implements DiffPolicy{ incCurrentWord(1); } - public String getWordSequence(int wordCount) { + @NotNull + public DiffString getWordSequence(int wordCount) { int start = myWords[myCurrentWord].getStart(); int end = myWords[myCurrentWord+wordCount-1].getEnd(); return myText.substring(start, end); @@ -341,22 +366,26 @@ public class ByWord implements DiffPolicy{ myCurrentWord += inserted; } + @NotNull public Word getCurrentWord() { return myWords[myCurrentWord]; } - public String getCurrentWordPrefix() { + @NotNull + public DiffString getCurrentWordPrefix() { return getCurrentWord().getPrefix(getProcessedOffset()); } - public String getCurrentWordPostfixAndOneMore() { + @NotNull + public DiffString getCurrentWordPostfixAndOneMore() { int nextStart = myCurrentWord < myWords.length - 1 ? myWords[myCurrentWord + 1].getStart() : myText.length(); Word word = getCurrentWord(); - String postfix = myText.substring(word.getEnd(), nextStart); - return postfix + (nextStart == myText.length() ? '\n' : myText.charAt(nextStart)); + DiffString postfix = myText.substring(word.getEnd(), nextStart); + return postfix.append(nextStart == myText.length() ? '\n' : myText.charAt(nextStart)); } - public String getNotProcessedTail() { + @NotNull + public DiffString getNotProcessedTail() { LOG.assertTrue(myCurrentWord == myWords.length); return myText.substring(myOffset, myText.length()); } @@ -365,7 +394,7 @@ public class ByWord implements DiffPolicy{ return myOffset == 0 ? '\n' : myText.charAt(myOffset - 1); } - public void addOneSide(String prefix, int wordCount) { + public void addOneSide(@NotNull DiffString prefix, int wordCount) { if (!prefix.isEmpty()) myBuilder.addOneSide(prefix, mySide); myBuilder.addOneSide(getWordSequence(wordCount), mySide); incCurrentWord(wordCount); diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffCorrection.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffCorrection.java index ee8db1c1447e..a97b1c502aa2 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffCorrection.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffCorrection.java @@ -16,7 +16,7 @@ package com.intellij.openapi.diff.impl.processing; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.diff.LineTokenizer; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; @@ -48,14 +48,18 @@ public interface DiffCorrection { } @Override - public void process(DiffFragment fragment, FragmentsCollector collector) throws FilesTooBigForDiffException { + public void process(@NotNull DiffFragment fragment, @NotNull FragmentsCollector collector) throws FilesTooBigForDiffException { + DiffString text1 = fragment.getText1(); + DiffString text2 = fragment.getText2(); if (!fragment.isEqual()) { if (myComparisonPolicy.isEqual(fragment)) - fragment = myComparisonPolicy.createFragment(fragment.getText1(), fragment.getText2()); + fragment = myComparisonPolicy.createFragment(text1, text2); collector.add(fragment); } else { - String[] lines1 = new LineTokenizer(fragment.getText1()).execute(); - String[] lines2 = new LineTokenizer(fragment.getText2()).execute(); + assert text1 != null; + assert text2 != null; + DiffString[] lines1 = text1.tokenize(); + DiffString[] lines2 = text2.tokenize(); LOG.assertTrue(lines1.length == lines2.length); for (int i = 0; i < lines1.length; i++) collector.addAll(myDiffPolicy.buildFragments(lines1[i], lines2[i])); @@ -77,45 +81,39 @@ public interface DiffCorrection { } @Override - public void process(DiffFragment fragment, FragmentsCollector collector) throws FilesTooBigForDiffException { + public void process(@NotNull DiffFragment fragment, @NotNull FragmentsCollector collector) throws FilesTooBigForDiffException { if (!fragment.isChange()) { collector.add(fragment); return; } - String text1 = fragment.getText1(); - String text2 = fragment.getText2(); + DiffString text1 = fragment.getText1(); + DiffString text2 = fragment.getText2(); while (StringUtil.startsWithChar(text1, '\n') || StringUtil.startsWithChar(text2, '\n')) { - String newLine1 = null; - String newLine2 = null; + DiffString newLine1 = null; + DiffString newLine2 = null; if (StringUtil.startsWithChar(text1, '\n')) { - newLine1 = "\n"; + newLine1 = DiffString.create("\n"); text1 = text1.substring(1); } if (StringUtil.startsWithChar(text2, '\n')) { - newLine2 = "\n"; + newLine2 = DiffString.create("\n"); text2 = text2.substring(1); } collector.add(new DiffFragment(newLine1, newLine2)); } - String spaces1 = leadingSpaces(text1); - String spaces2 = leadingSpaces(text2); + DiffString spaces1 = text1.getLeadingSpaces(); + DiffString spaces2 = text2.getLeadingSpaces(); if (spaces1.isEmpty() && spaces2.isEmpty()) { DiffFragment trailing = myComparisonPolicy.createFragment(text1, text2); collector.add(trailing); return; } collector.addAll(myDiffPolicy.buildFragments(spaces1, spaces2)); - DiffFragment textFragment = myComparisonPolicy.createFragment(text1.substring(spaces1.length(), text1.length()), - text2.substring(spaces2.length(), text2.length())); + DiffFragment textFragment = myComparisonPolicy + .createFragment(text1.substring(spaces1.length(), text1.length()), text2.substring(spaces2.length(), text2.length())); collector.add(textFragment); } - private String leadingSpaces(String text) { - int i = 0; - while (i < text.length() && text.charAt(i) == ' ') i++; - return text.substring(0, i); - } - @Override public DiffFragment[] correct(DiffFragment[] fragments) throws FilesTooBigForDiffException { FragmentsCollector collector = new FragmentsCollector(); @@ -125,7 +123,7 @@ public interface DiffCorrection { } interface FragmentProcessor<Collector> { - void process(DiffFragment fragment, Collector collector) throws FilesTooBigForDiffException; + void process(@NotNull DiffFragment fragment, @NotNull Collector collector) throws FilesTooBigForDiffException; } class BaseFragmentRunner<ActualRunner extends BaseFragmentRunner> { @@ -158,8 +156,7 @@ public interface DiffCorrection { } } - // todo think where - public static int getTextLength(String text) { + public static int getTextLength(DiffString text) { return text != null ? text.length() : 0; } @@ -224,7 +221,7 @@ public interface DiffCorrection { } @Override - public void process(DiffFragment fragment, FragmentBuffer buffer) { + public void process(@NotNull DiffFragment fragment, @NotNull FragmentBuffer buffer) { if (fragment.isOneSide()) buffer.markIfNone(DEFAULT_MODE); else buffer.add(fragment); } @@ -243,7 +240,7 @@ public interface DiffCorrection { } @Override - public void process(DiffFragment fragment, FragmentBuffer buffer) { + public void process(@NotNull DiffFragment fragment, @NotNull FragmentBuffer buffer) { if (fragment.isEqual()) buffer.markIfNone(EQUAL_MODE); else if (ComparisonPolicy.TRIM_SPACE.isEqual(fragment)) buffer.markIfNone(FORMATTING_MODE); else buffer.add(fragment); @@ -273,10 +270,10 @@ public interface DiffCorrection { } @Override - public void process(DiffFragment fragment, FragmentBuffer buffer) { + public void process(@NotNull DiffFragment fragment, @NotNull FragmentBuffer buffer) { if (fragment.isEqual()) buffer.add(fragment); else if (fragment.isOneSide()) { - String text = FragmentSide.chooseSide(fragment).getText(fragment); + DiffString text = FragmentSide.chooseSide(fragment).getText(fragment); if (StringUtil.endsWithChar(text, '\n')) buffer.add(fragment); else diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffPolicy.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffPolicy.java index 21cfc3d1c679..4547252456f7 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffPolicy.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffPolicy.java @@ -15,13 +15,20 @@ */ package com.intellij.openapi.diff.impl.processing; -import com.intellij.openapi.diff.LineTokenizer; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; public interface DiffPolicy { - DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException; + @NotNull + DiffFragment[] buildFragments(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException; + + @NotNull + @TestOnly + DiffFragment[] buildFragments(@NotNull String text1, @NotNull String text2) throws FilesTooBigForDiffException; DiffPolicy LINES_WO_FORMATTING = new LineBlocks(ComparisonPolicy.IGNORE_SPACE); DiffPolicy DEFAULT_LINES = new LineBlocks(ComparisonPolicy.DEFAULT); @@ -33,10 +40,17 @@ public interface DiffPolicy { myComparisonPolicy = comparisonPolicy; } + @NotNull + @TestOnly + public DiffFragment[] buildFragments(@NotNull String text1, @NotNull String text2) throws FilesTooBigForDiffException { + return buildFragments(DiffString.create(text1), DiffString.create(text2)); + } + + @NotNull @Override - public DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException { - String[] strings1 = new LineTokenizer(text1).execute(); - String[] strings2 = new LineTokenizer(text2).execute(); + public DiffFragment[] buildFragments(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException { + DiffString[] strings1 = text1.tokenize(); + DiffString[] strings2 = text2.tokenize(); return myComparisonPolicy.buildDiffFragmentsFromLines(strings1, strings2); } @@ -49,13 +63,20 @@ public interface DiffPolicy { myComparisonPolicy = comparisonPolicy; } + @NotNull + @TestOnly + public DiffFragment[] buildFragments(@NotNull String text1, @NotNull String text2) throws FilesTooBigForDiffException { + return buildFragments(DiffString.create(text1), DiffString.create(text2)); + } + + @NotNull @Override - public DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException { + public DiffFragment[] buildFragments(@NotNull DiffString text1, @NotNull DiffString text2) throws FilesTooBigForDiffException { return myComparisonPolicy.buildFragments(splitByChar(text1), splitByChar(text2)); } - private String[] splitByChar(String text) { - String[] result = new String[text.length()]; + private static DiffString[] splitByChar(@NotNull DiffString text) { + DiffString[] result = new DiffString[text.length()]; for (int i = 0; i < result.length; i++) { result[i] = text.substring(i, i + 1); } diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/Formatting.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/Formatting.java index 8a520f2ffcb5..a4eaf356b23d 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/Formatting.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/Formatting.java @@ -15,10 +15,18 @@ */ package com.intellij.openapi.diff.impl.processing; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; public class Formatting extends Word { - public Formatting(String text, TextRange range) { + @TestOnly + public Formatting(@NotNull String baseText, @NotNull TextRange range) { + this(DiffString.create(baseText), range); + } + + public Formatting(@NotNull DiffString text, @NotNull TextRange range) { super(text, range); } diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/LineFragmentsCollector.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/LineFragmentsCollector.java index fd8a22d974bd..75342869c566 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/LineFragmentsCollector.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/LineFragmentsCollector.java @@ -15,11 +15,14 @@ */ package com.intellij.openapi.diff.impl.processing; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.util.TextDiffTypeEnum; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -30,14 +33,14 @@ class LineFragmentsCollector { private int myOffset1 = 0; private int myOffset2 = 0; - private LineFragment addFragment(TextDiffTypeEnum type, String text1, String text2) { + @NotNull + private LineFragment addFragment(@Nullable TextDiffTypeEnum type, @Nullable DiffString text1, @Nullable DiffString text2) { int lines1 = countLines(text1); int lines2 = countLines(text2); int endOffset1 = myOffset1 + getLength(text1); int endOffset2 = myOffset2 + getLength(text2); - LineFragment lineFragment = new LineFragment(myLine1, lines1, myLine2, lines2, type, - new TextRange(myOffset1, endOffset1), - new TextRange(myOffset2, endOffset2)); + LineFragment lineFragment = + new LineFragment(myLine1, lines1, myLine2, lines2, type, new TextRange(myOffset1, endOffset1), new TextRange(myOffset2, endOffset2)); myLine1 += lines1; myLine2 += lines2; myOffset1 = endOffset1; @@ -46,18 +49,19 @@ class LineFragmentsCollector { return lineFragment; } - public LineFragment addDiffFragment(DiffFragment fragment) { + @NotNull + public LineFragment addDiffFragment(@NotNull DiffFragment fragment) { return addFragment(getType(fragment), fragment.getText1(), fragment.getText2()); } - static int getLength(String text) { + static int getLength(@Nullable DiffString text) { return text == null ? 0 : text.length(); } - private static int countLines(String text) { + private static int countLines(@Nullable DiffString text) { if (text == null || text.isEmpty()) return 0; int count = StringUtil.countNewLines(text); - if (text.charAt(text.length()-1) != '\n') count++; + if (text.charAt(text.length() - 1) != '\n') count++; return count; } @@ -65,7 +69,8 @@ class LineFragmentsCollector { return myLineFragments; } - static TextDiffTypeEnum getType(DiffFragment fragment) { + @Nullable + static TextDiffTypeEnum getType(@NotNull DiffFragment fragment) { TextDiffTypeEnum type; if (fragment.getText1() == null) type = TextDiffTypeEnum.INSERT; else if (fragment.getText2() == null) type = TextDiffTypeEnum.DELETED; diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/UniteSameType.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/UniteSameType.java index ee166ceabb1e..bf21f1066ad2 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/UniteSameType.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/UniteSameType.java @@ -16,10 +16,12 @@ package com.intellij.openapi.diff.impl.processing; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.Util; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.NotNull; class UniteSameType implements DiffCorrection { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.UniteSameType"); @@ -29,7 +31,8 @@ class UniteSameType implements DiffCorrection { return unitSameTypes(covertSequentialOneSideToChange(unitSameTypes(fragments))); } - private DiffFragment[] unitSameTypes(DiffFragment[] fragments) { + @NotNull + private static DiffFragment[] unitSameTypes(@NotNull DiffFragment[] fragments) { if (fragments.length < 2) return fragments; DiffCorrection.FragmentsCollector collector = new DiffCorrection.FragmentsCollector(); DiffFragment previous = fragments[0]; @@ -47,7 +50,8 @@ class UniteSameType implements DiffCorrection { return collector.toArray(); } - private DiffFragment[] covertSequentialOneSideToChange(DiffFragment[] fragments) { + @NotNull + private static DiffFragment[] covertSequentialOneSideToChange(@NotNull DiffFragment[] fragments) { if (fragments.length < 2) return fragments; DiffCorrection.FragmentsCollector collector = new DiffCorrection.FragmentsCollector(); // DiffFragment previous = fragments[0]; @@ -58,9 +62,10 @@ class UniteSameType implements DiffCorrection { if (previous == null) previous = fragment; else { FragmentSide side = FragmentSide.chooseSide(fragment); - String previousText = side.getText(previous); - if (previousText == null) previousText = ""; - previous = side.createFragment(previousText + side.getText(fragment), side.getOtherText(previous), true); + DiffString previousText = side.getText(previous); + if (previousText == null) previousText = DiffString.EMPTY; + previous = side.createFragment(DiffString.concatenateNullable(previousText, side.getText(fragment)), + side.getOtherText(previous), true); } } else { if (previous != null) collector.add(previous); diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/Word.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/Word.java index 3279fc4c1529..d9d67dc3e6f6 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/Word.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/Word.java @@ -16,22 +16,32 @@ package com.intellij.openapi.diff.impl.processing; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; public class Word { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.Word"); - private final String myText; - private final TextRange myRange; + @NotNull private final DiffString myBaseText; + @NotNull private final TextRange myRange; + @NotNull private final DiffString myText; - public Word(String text, TextRange range) { - myText = text; + @TestOnly + public Word(@NotNull String baseText, @NotNull TextRange range) { + this(DiffString.create(baseText), range); + } + + public Word(@NotNull DiffString baseText, @NotNull TextRange range) { + myBaseText = baseText; myRange = range; + myText = myBaseText.substring(myRange.getStartOffset(), myRange.getEndOffset()); LOG.assertTrue(myRange.getStartOffset() >= 0); LOG.assertTrue(myRange.getEndOffset() >= myRange.getStartOffset(), myRange); } public int hashCode() { - return getText().hashCode(); + return myText.hashCode(); } public boolean equals(Object obj) { @@ -40,15 +50,17 @@ public class Word { return getText().equals(other.getText()); } - public String getText() { - return myRange.substring(myText); + @NotNull + public DiffString getText() { + return myText; } - public String getPrefix(int fromPosition) { - LOG.assertTrue(fromPosition >= 0, "" + fromPosition); + @NotNull + public DiffString getPrefix(int fromPosition) { + LOG.assertTrue(fromPosition >= 0, fromPosition); int wordStart = myRange.getStartOffset(); - LOG.assertTrue(fromPosition <= wordStart, "" + fromPosition + " " + wordStart); - return myText.substring(fromPosition, wordStart); + LOG.assertTrue(fromPosition <= wordStart, fromPosition + " " + wordStart); + return myBaseText.substring(fromPosition, wordStart); } public int getEnd() { @@ -60,7 +72,7 @@ public class Word { } public String toString() { - return getText(); + return myText.toString(); } public boolean isWhitespace() { @@ -70,10 +82,10 @@ public class Word { public boolean atEndOfLine() { int start = myRange.getStartOffset(); if (start == 0) return true; - if (myText.charAt(start - 1) == '\n') return true; + if (myBaseText.charAt(start - 1) == '\n') return true; int end = myRange.getEndOffset(); - if (end == myText.length()) return true; - if (myText.charAt(end) == '\n') return true; + if (end == myBaseText.length()) return true; + if (myBaseText.charAt(end) == '\n') return true; return false; } } diff --git a/platform/util/src/com/intellij/openapi/diff/impl/string/DiffString.java b/platform/util/src/com/intellij/openapi/diff/impl/string/DiffString.java new file mode 100644 index 000000000000..76aa43418ccc --- /dev/null +++ b/platform/util/src/com/intellij/openapi/diff/impl/string/DiffString.java @@ -0,0 +1,420 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.diff.impl.string; + +import com.intellij.openapi.diff.LineTokenizerBase; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class DiffString implements CharSequence { + @NotNull public static final DiffString EMPTY = new DiffString(new char[0], 0, 0); + + @NotNull private final char[] myData; + private final int myStart; + private final int myLength; + private int myHash; + + @Nullable + public static DiffString createNullable(@Nullable String string) { + if (string == null) return null; + return create(string); + } + + @NotNull + public static DiffString create(@NotNull String string) { + if (string.isEmpty()) return EMPTY; + return create(string.toCharArray()); + } + + @NotNull + static DiffString create(@NotNull char[] data) { + return create(data, 0, data.length); + } + + @NotNull + static DiffString create(@NotNull char[] data, int start, int length) { + if (length == 0) return EMPTY; + checkBounds(start, length, data.length); + return new DiffString(data, start, length); + } + + private DiffString(@NotNull char[] data, int start, int length) { + myData = data; + myStart = start; + myLength = length; + } + + @Override + public int length() { + return myLength; + } + + public boolean isEmpty() { + return myLength == 0; + } + + @Override + public char charAt(int index) { + if (index < 0 || index >= myLength) { + throw new StringIndexOutOfBoundsException(index); + } + return data(index); + } + + public char data(int index) { + return myData[myStart + index]; + } + + @NotNull + public DiffString substring(int start) { + return substring(start, myLength); + } + + @NotNull + public DiffString substring(int start, int end) { + if (start == 0 && end == myLength) return this; + checkBounds(start, end - start, myLength); + return create(myData, myStart + start, end - start); + } + + @Override + public DiffString subSequence(int start, int end) { + return substring(start, end); + } + + @NotNull + @Override + public String toString() { + return new String(myData, myStart, myLength); + } + + @NotNull + public DiffString copy() { + return create(Arrays.copyOfRange(myData, myStart, myStart + myLength)); + } + + public void copyData(@NotNull char[] dst, int start) { + checkBounds(start, myLength, dst.length); + System.arraycopy(myData, myStart, dst, start, myLength); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DiffString that = (DiffString)o; + + if (myLength != that.myLength) return false; + if (hashCode() != that.hashCode()) return false; + for (int i = 0; i < myLength; i++) { + if (data(i) != that.data(i)) return false; + } + + return true; + } + + @Override + public int hashCode() { + int h = myHash; + if (h == 0) { + h = StringUtil.stringHashCode(myData, myStart, myStart + myLength); + if (h == 0) h = 1; + myHash = h; + } + return h; + } + + @Nullable + public static DiffString concatenateNullable(@Nullable DiffString s1, @Nullable DiffString s2) { + if (s1 == null || s2 == null) { + if (s1 != null) return s1; + if (s2 != null) return s2; + return null; + } + + return concatenate(s1, s2); + } + + @NotNull + public static DiffString concatenate(@NotNull DiffString s1, @NotNull DiffString s2) { + if (s1.isEmpty()) return s2; + if (s2.isEmpty()) return s1; + + if (s1.myData == s2.myData && s1.myStart + s1.myLength == s2.myStart) { + return create(s1.myData, s1.myStart, s1.myLength + s2.myLength); + } + + char[] data = new char[s1.myLength + s2.myLength]; + System.arraycopy(s1.myData, s1.myStart, data, 0, s1.myLength); + System.arraycopy(s2.myData, s2.myStart, data, s1.myLength, s2.myLength); + return create(data); + } + + public static boolean canInplaceConcatenate(@NotNull DiffString s1, @NotNull DiffString s2) { + if (s1.isEmpty()) return true; + if (s2.isEmpty()) return true; + + if (s1.myData == s2.myData && s1.myStart + s1.myLength == s2.myStart) { + return true; + } + + return false; + } + + @NotNull + public static DiffString concatenateCopying(@NotNull DiffString[] strings) { + return concatenateCopying(strings, 0, strings.length); + } + + @NotNull + public static DiffString concatenateCopying(@NotNull DiffString[] strings, int start, int length) { + checkBounds(start, length, strings.length); + + int len = 0; + for (int i = 0; i < length; i++) { + DiffString string = strings[start + i]; + len += string == null ? 0 : string.myLength; + } + + if (len == 0) return EMPTY; + + char[] data = new char[len]; + int index = 0; + for (int i = 0; i < length; i++) { + DiffString string = strings[start + i]; + if (string == null || string.isEmpty()) continue; + System.arraycopy(string.myData, string.myStart, data, index, string.myLength); + index += string.myLength; + } + return create(data); + } + + @NotNull + public static DiffString concatenate(@NotNull DiffString s, char c) { + if (s.myStart + s.myLength < s.myData.length && s.data(s.myLength) == c) { + return create(s.myData, s.myStart, s.myLength + 1); + } + + char[] data = new char[s.myLength + 1]; + System.arraycopy(s.myData, s.myStart, data, 0, s.myLength); + data[s.myLength] = c; + return create(data); + } + + @NotNull + public static DiffString concatenate(char c, @NotNull DiffString s) { + if (s.myStart > 0 && s.data(-1) == c) { + return create(s.myData, s.myStart - 1, s.myLength + 1); + } + + char[] data = new char[s.myLength + 1]; + System.arraycopy(s.myData, s.myStart, data, 1, s.myLength); + data[0] = c; + return create(data); + } + + @NotNull + public static DiffString concatenate(@NotNull DiffString[] strings) { + return concatenate(strings, 0, strings.length); + } + + @NotNull + public static DiffString concatenate(@NotNull DiffString[] strings, int start, int length) { + checkBounds(start, length, strings.length); + + char[] data = null; + int startIndex = 0; + int endIndex = 0; + + boolean linearized = true; + for (int i = 0; i < length; i++) { + DiffString string = strings[start + i]; + if (string == null || string.isEmpty()) continue; + if (data == null) { + data = string.myData; + startIndex = string.myStart; + endIndex = string.myStart + string.myLength; + continue; + } + if (data != string.myData || string.myStart != endIndex) { + linearized = false; + break; + } + endIndex += string.myLength; + } + + if (linearized) { + if (data == null) return EMPTY; + return create(data, startIndex, endIndex - startIndex); + } + + return concatenateCopying(strings, start, length); + } + + @NotNull + public DiffString append(char c) { + return concatenate(this, c); + } + + @NotNull + public DiffString preappend(char c) { + return concatenate(c, this); + } + + public static boolean isWhiteSpace(char c) { + return StringUtil.isWhiteSpace(c); + } + + public boolean isEmptyOrSpaces() { + if (isEmpty()) return true; + + for (int i = 0; i < myLength; i++) { + if (!isWhiteSpace(data(i))) return false; + } + return true; + } + + @NotNull + public DiffString trim() { + int start = 0; + int end = myLength; + + while (start < end && isWhiteSpace(data(start))) start++; + while (end > start && isWhiteSpace(data(end - 1))) end--; + + return substring(start, end); + } + + @NotNull + public DiffString trimLeading() { + int i = 0; + + while (i < myLength && isWhiteSpace(data(i))) i++; + + return substring(i, myLength); + } + + @NotNull + public DiffString trimTrailing() { + int end = myLength; + + while (end > 0 && isWhiteSpace(data(end - 1))) end--; + + return substring(0, end); + } + + @NotNull + public DiffString getLeadingSpaces() { + int i = 0; + + while (i < myLength && data(i) == ' ') i++; + + return substring(0, i); + } + + @NotNull + public DiffString skipSpaces() { + DiffString s = trim(); + int count = 0; + for (int i = 0; i < s.myLength; i++) { + if (isWhiteSpace(s.data(i))) count++; + } + if (count == 0) return s; + + char[] data = new char[s.myLength - count]; + int index = 0; + for (int i = 0; i < s.myLength; i++) { + if (isWhiteSpace(s.data(i))) continue; + data[index] = s.data(i); + index++; + } + return create(data); + } + + public int indexOf(char c) { + return StringUtil.indexOf(this, c); + } + + public boolean endsWith(char c) { + if (isEmpty()) return false; + return data(myLength - 1) == c; + } + + public static void checkBounds(int start, int length, int maxLength) { + if (start < 0) { + throw new StringIndexOutOfBoundsException(start); + } + if (length < 0) { + throw new StringIndexOutOfBoundsException(length); + } + if (start + length > maxLength) { + throw new StringIndexOutOfBoundsException(start + length); + } + } + + @NotNull + public DiffString[] tokenize() { + return new LineTokenizer(this).execute(); + } + + public static class LineTokenizer extends LineTokenizerBase<DiffString> { + @NotNull private final DiffString myText; + + public LineTokenizer(@NotNull DiffString text) { + myText = text; + } + + @NotNull + public DiffString[] execute() { + ArrayList<DiffString> lines = new ArrayList<DiffString>(); + doExecute(lines); + return ContainerUtil.toArray(lines, new DiffString[lines.size()]); + } + + @Override + protected void addLine(List<DiffString> lines, int start, int end, boolean appendNewLine) { + if (appendNewLine) { + lines.add(myText.substring(start, end).append('\n')); + } + else { + lines.add(myText.substring(start, end)); + } + } + + @Override + protected char charAt(int index) { + return myText.data(index); + } + + @Override + protected int length() { + return myText.length(); + } + + @NotNull + @Override + protected String substring(int start, int end) { + return myText.substring(start, end).toString(); + } + } +} diff --git a/platform/util/src/com/intellij/openapi/diff/impl/string/DiffStringBuilder.java b/platform/util/src/com/intellij/openapi/diff/impl/string/DiffStringBuilder.java new file mode 100644 index 000000000000..f1a700f22e15 --- /dev/null +++ b/platform/util/src/com/intellij/openapi/diff/impl/string/DiffStringBuilder.java @@ -0,0 +1,82 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.diff.impl.string; + +import com.intellij.openapi.diff.impl.string.DiffString; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +public class DiffStringBuilder implements CharSequence { + @NotNull private char[] myData; + private int myLength; + + public DiffStringBuilder() { + this(16); + } + + public DiffStringBuilder(int len) { + myData = new char[len]; + myLength = 0; + } + + @Override + public int length() { + return myLength; + } + + @Override + public char charAt(int index) { + if (index < 0 || index >= myLength) { + throw new StringIndexOutOfBoundsException(index); + } + return myData[index]; + } + + @Override + @NotNull + public CharSequence subSequence(int start, int end) { + DiffString.checkBounds(start, end, myLength); + return DiffString.create(myData, start, end - start); + } + + @NotNull + public DiffString toDiffString() { + return DiffString.create(myData, 0, myLength); + } + + @Override + @NotNull + public String toString() { + return toDiffString().toString(); + } + + private void ensureCapacityInternal(int neededCapacity) { + if (neededCapacity > myData.length) { + int newCapacity = myData.length; + while (newCapacity < neededCapacity) newCapacity *= 2; + + myData = Arrays.copyOf(myData, newCapacity); + } + } + + public void append(@NotNull DiffString s) { + if (s.isEmpty()) return; + ensureCapacityInternal(myLength + s.length()); + s.copyData(myData, myLength); + myLength += s.length(); + } +} diff --git a/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java b/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java index 72dc236f0935..909c44db199b 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java @@ -19,6 +19,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -104,4 +105,15 @@ public class JDOMExternalizer { } } } + + public static List<String> loadStringsList(Element element, String rootName, String attrName) { + final List<String> paths = new LinkedList<String>(); + if (element != null) { + @NotNull final List list = element.getChildren(rootName); + for (Object o : list) { + paths.add(((Element)o).getAttribute(attrName).getValue()); + } + } + return paths; + } }
\ No newline at end of file diff --git a/platform/util/src/com/intellij/openapi/util/Key.java b/platform/util/src/com/intellij/openapi/util/Key.java index 949cb3e1ba46..09ef12949ccf 100644 --- a/platform/util/src/com/intellij/openapi/util/Key.java +++ b/platform/util/src/com/intellij/openapi/util/Key.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. @@ -42,6 +42,7 @@ public class Key<T> { allKeys.put(myIndex, this); } + // made final because many classes depend on one-to-one key index <-> key instance relationship. See e.g. UserDataHolderBase public final int hashCode() { return myIndex; } diff --git a/platform/util/src/com/intellij/util/LocalTimeCounter.java b/platform/util/src/com/intellij/util/LocalTimeCounter.java index 1cfbdb7e4df0..41b09b723197 100644 --- a/platform/util/src/com/intellij/util/LocalTimeCounter.java +++ b/platform/util/src/com/intellij/util/LocalTimeCounter.java @@ -18,12 +18,14 @@ package com.intellij.util; import java.util.concurrent.atomic.AtomicLong; public class LocalTimeCounter { + /** + * VirtualFile.modificationStamp is kept modulo this mask, and is compared with other stamps. Let's avoid accidental stamp inequalities + * by normalizing all of them. + */ + public static final int TIME_MASK = 0x00ffffff; private static final AtomicLong ourCurrentTime = new AtomicLong(); - private LocalTimeCounter() { - } - public static long currentTime() { - return ourCurrentTime.incrementAndGet(); + return TIME_MASK & (int)ourCurrentTime.incrementAndGet(); } }
\ No newline at end of file diff --git a/platform/util/src/com/intellij/util/diff/PatienceIntLCS.java b/platform/util/src/com/intellij/util/diff/PatienceIntLCS.java index 5acb8272c8fb..f20353e48ccf 100644 --- a/platform/util/src/com/intellij/util/diff/PatienceIntLCS.java +++ b/platform/util/src/com/intellij/util/diff/PatienceIntLCS.java @@ -120,7 +120,7 @@ public class PatienceIntLCS { } private int matchForward(int offset1, int offset2) { - final int size = Math.min(myCount1 - offset1, myCount2 - offset2); + final int size = Math.min(myCount1 + myStart1 - offset1, myCount2 + myStart2 - offset2); int idx = 0; for (int i = 0; i < size; i++) { if (!(myFirst[offset1 + i] == mySecond[offset2 + i])) break; diff --git a/platform/util/src/com/intellij/util/io/DataExternalizer.java b/platform/util/src/com/intellij/util/io/DataExternalizer.java index 44454294e398..f252424466be 100644 --- a/platform/util/src/com/intellij/util/io/DataExternalizer.java +++ b/platform/util/src/com/intellij/util/io/DataExternalizer.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. @@ -15,12 +15,14 @@ */ package com.intellij.util.io; +import org.jetbrains.annotations.NotNull; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; public interface DataExternalizer<T> { - void save(DataOutput out, T value) throws IOException; + void save(@NotNull DataOutput out, T value) throws IOException; - T read(DataInput in) throws IOException; + T read(@NotNull DataInput in) throws IOException; } diff --git a/platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.java b/platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.java index 1621cf3bc22c..a662aae3f527 100644 --- a/platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.java +++ b/platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.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. @@ -37,13 +37,13 @@ public class EnumeratorStringDescriptor implements KeyDescriptor<String> { } @Override - public void save(final DataOutput storage, @NotNull final String value) throws IOException { + public void save(@NotNull final DataOutput storage, @NotNull final String value) throws IOException { final byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); IOUtil.writeUTFFast(buffer, storage, value); } @Override - public String read(final DataInput storage) throws IOException { + public String read(@NotNull final DataInput storage) throws IOException { final byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); return IOUtil.readUTFFast(buffer, storage); } diff --git a/platform/util/src/com/intellij/util/io/ExternalIntegerKeyDescriptor.java b/platform/util/src/com/intellij/util/io/ExternalIntegerKeyDescriptor.java index 009581e5a098..cb3e1466295a 100644 --- a/platform/util/src/com/intellij/util/io/ExternalIntegerKeyDescriptor.java +++ b/platform/util/src/com/intellij/util/io/ExternalIntegerKeyDescriptor.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. @@ -19,6 +19,8 @@ */ package com.intellij.util.io; +import org.jetbrains.annotations.NotNull; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -35,12 +37,12 @@ public class ExternalIntegerKeyDescriptor implements KeyDescriptor<Integer> { } @Override - public void save(final DataOutput out, final Integer value) throws IOException { + public void save(@NotNull final DataOutput out, final Integer value) throws IOException { DataInputOutputUtil.writeINT(out, value.intValue()); } @Override - public Integer read(final DataInput in) throws IOException { + public Integer read(@NotNull final DataInput in) throws IOException { return DataInputOutputUtil.readINT(in); } }
\ No newline at end of file diff --git a/platform/util/src/com/intellij/util/io/InlineKeyDescriptor.java b/platform/util/src/com/intellij/util/io/InlineKeyDescriptor.java index 8cf030a5d975..d64df97e574b 100644 --- a/platform/util/src/com/intellij/util/io/InlineKeyDescriptor.java +++ b/platform/util/src/com/intellij/util/io/InlineKeyDescriptor.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. @@ -19,6 +19,8 @@ */ package com.intellij.util.io; +import org.jetbrains.annotations.NotNull; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -41,14 +43,14 @@ public abstract class InlineKeyDescriptor<T> implements KeyDescriptor<T> { } @Override - public final void save(DataOutput out, T value) throws IOException { + public final void save(@NotNull DataOutput out, T value) throws IOException { int v = toInt(value); if (myCompactFormat) DataInputOutputUtil.writeINT(out, v); else out.writeInt(v); } @Override - public final T read(DataInput in) throws IOException { + public final T read(@NotNull DataInput in) throws IOException { int n; if (myCompactFormat) n = DataInputOutputUtil.readINT(in); else n = in.readInt(); diff --git a/platform/util/src/com/intellij/util/io/MappedFileInputStream.java b/platform/util/src/com/intellij/util/io/MappedFileInputStream.java index c67c816e6578..10a57dcf4c5c 100644 --- a/platform/util/src/com/intellij/util/io/MappedFileInputStream.java +++ b/platform/util/src/com/intellij/util/io/MappedFileInputStream.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. @@ -25,24 +25,24 @@ import java.io.IOException; import java.io.InputStream; public class MappedFileInputStream extends InputStream { - private ResizeableMappedFile raf; + private final ResizeableMappedFile raf; private int cur; private long limit; - public MappedFileInputStream(final ResizeableMappedFile raf, final long pos, final long limit) { + public MappedFileInputStream(@NotNull ResizeableMappedFile raf, final long pos, final long limit) { this.raf = raf; setup(pos, limit); } + public MappedFileInputStream(@NotNull ResizeableMappedFile raf, final long pos) throws IOException { + this(raf, pos, raf.length()); + } + public void setup(final long pos, final long limit) { this.cur = (int)pos; this.limit = limit; } - public MappedFileInputStream(final ResizeableMappedFile raf, final long pos) throws IOException { - this(raf, pos, raf.length()); - } - @Override public int available() { @@ -67,7 +67,7 @@ public class MappedFileInputStream extends InputStream { } @Override - public int read( @NotNull byte[] b, int offset, int length ) throws IOException + public int read(@NotNull byte[] b, int offset, int length ) throws IOException { //only allow a read of the amount available. if( length > available() ) diff --git a/platform/util/src/com/intellij/util/io/NullableDataExternalizer.java b/platform/util/src/com/intellij/util/io/NullableDataExternalizer.java index 7f8bba853fb4..897fa7d2084b 100644 --- a/platform/util/src/com/intellij/util/io/NullableDataExternalizer.java +++ b/platform/util/src/com/intellij/util/io/NullableDataExternalizer.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. @@ -15,6 +15,7 @@ */ package com.intellij.util.io; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataOutput; @@ -32,7 +33,7 @@ public class NullableDataExternalizer<T> implements DataExternalizer<T> { } @Override - public void save(DataOutput out, T value) throws IOException { + public void save(@NotNull DataOutput out, T value) throws IOException { if (value == null) { out.writeBoolean(false); } else { @@ -43,7 +44,7 @@ public class NullableDataExternalizer<T> implements DataExternalizer<T> { @Override @Nullable - public T read(DataInput in) throws IOException { + public T read(@NotNull DataInput in) throws IOException { final boolean isDefined = in.readBoolean(); if (isDefined) { return myNotNullExternalizer.read(in); diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 5cb7ad4bf206..6903c6bcca14 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -45,6 +45,7 @@ import javax.swing.text.DefaultEditorKit; import javax.swing.text.JTextComponent; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; +import javax.swing.undo.UndoManager; import java.awt.*; import java.awt.event.*; import java.awt.font.FontRenderContext; @@ -1584,6 +1585,7 @@ public class UIUtil { g.setComposite(X_RENDER_ACTIVE.getValue() ? AlphaComposite.SrcOver : AlphaComposite.Src); } + /** @see #pump() */ @TestOnly public static void dispatchAllInvocationEvents() { assert SwingUtilities.isEventDispatchThread() : Thread.currentThread(); @@ -1603,6 +1605,7 @@ public class UIUtil { } } + /** @see #dispatchAllInvocationEvents() */ @TestOnly public static void pump() { assert !SwingUtilities.isEventDispatchThread(); @@ -2778,4 +2781,28 @@ public class UIUtil { } return false; } + + public static void addUndoRedoActions(JTextComponent textComponent) { + final UndoManager undoManager = new UndoManager(); + textComponent.getDocument().addUndoableEditListener(undoManager); + textComponent.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, SystemInfo.isMac? InputEvent.META_MASK : InputEvent.CTRL_MASK), "undoKeystroke"); + textComponent.getActionMap().put("undoKeystroke", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (undoManager.canUndo()) { + undoManager.undo(); + } + } + }); + textComponent.getInputMap().put( + KeyStroke.getKeyStroke(KeyEvent.VK_Z, (SystemInfo.isMac? InputEvent.META_MASK : InputEvent.CTRL_MASK) | InputEvent.SHIFT_MASK), "redoKeystroke"); + textComponent.getActionMap().put("redoKeystroke", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (undoManager.canRedo()) { + undoManager.redo(); + } + } + }); + } } diff --git a/platform/util/src/com/intellij/util/xmlb/TextBinding.java b/platform/util/src/com/intellij/util/xmlb/TextBinding.java index a195b3b6b134..57cc3ef79315 100644 --- a/platform/util/src/com/intellij/util/xmlb/TextBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/TextBinding.java @@ -32,6 +32,7 @@ public class TextBinding implements Binding { @Override public Object serialize(Object o, Object context, SerializationFilter filter) { final Object v = myAccessor.read(o); + if (v == null) return context; final Object node = myBinding.serialize(v, context, filter); return new Text(((Content)node).getValue()); diff --git a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java index d70588834481..7a147e074468 100644 --- a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java +++ b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java @@ -1029,6 +1029,31 @@ public class XmlSerializerTest extends TestCase { } } + public static class ConversionFromTextToAttributeBean { + @Property(surroundWithTag = false) + public ConditionBean myConditionBean = new ConditionBean(); + } + @Tag("condition") + public static class ConditionBean { + @Attribute("expression") + public String myNewCondition; + @Text + public String myOldCondition; + } + + public void testConversionFromTextToAttribute() { + ConversionFromTextToAttributeBean bean = new ConversionFromTextToAttributeBean(); + bean.myConditionBean.myOldCondition = "2+2"; + doSerializerTest("<ConversionFromTextToAttributeBean>\n" + + " <condition>2+2</condition>\n" + + "</ConversionFromTextToAttributeBean>", bean); + + bean = new ConversionFromTextToAttributeBean(); + bean.myConditionBean.myNewCondition = "2+2"; + doSerializerTest("<ConversionFromTextToAttributeBean>\n" + + " <condition expression=\"2+2\" />\n" + + "</ConversionFromTextToAttributeBean>", bean); + } public void testDeserializeInto() throws Exception { BeanWithPublicFields bean = new BeanWithPublicFields(); diff --git a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java index 75918b5b56ca..9a78602ac8de 100644 --- a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java +++ b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java @@ -354,23 +354,31 @@ public class PatchReader { PatchHunk hunk = new PatchHunk(startLineBefore-1, startLineBefore+linesBefore-1, startLineAfter-1, startLineAfter+linesAfter-1); PatchLine lastLine = null; - int numLines = linesBefore + linesAfter; + int before = 0; + int after = 0; while (iterator.hasNext()) { String hunkCurLine = iterator.next(); - -- numLines; if (lastLine != null && hunkCurLine.startsWith(NO_NEWLINE_SIGNATURE)) { lastLine.setSuppressNewLine(true); continue; } - if (hunkCurLine.startsWith("--- ") && numLines == 0) { - iterator.previous(); - break; - } - lastLine = parsePatchLine(hunkCurLine, 1); + lastLine = parsePatchLine(hunkCurLine, 1, before < linesBefore || after < linesAfter); if (lastLine == null) { iterator.previous(); break; } + switch (lastLine.getType()) { + case CONTEXT: + before++; + after++; + break; + case ADD: + after++; + break; + case REMOVE: + before++; + break; + } hunk.addLine(lastLine); } return hunk; @@ -389,11 +397,16 @@ public class PatchReader { @Nullable private static PatchLine parsePatchLine(final String line, final int prefixLength) { + return parsePatchLine(line, prefixLength, true); + } + + @Nullable + private static PatchLine parsePatchLine(final String line, final int prefixLength, boolean expectMeaningfulLines) { PatchLine.Type type; - if (line.startsWith("+")) { + if (line.startsWith("+") && expectMeaningfulLines) { type = PatchLine.Type.ADD; } - else if (line.startsWith("-")) { + else if (line.startsWith("-") && expectMeaningfulLines) { type = PatchLine.Type.REMOVE; } else if (line.startsWith(" ") || line.length() == 0) { diff --git a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java index 7dc87ca57dc2..cbf110a9fe9d 100644 --- a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java +++ b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java @@ -15,7 +15,7 @@ */ package com.intellij.openapi.diff.impl.patch; -import com.intellij.openapi.diff.LineTokenizer; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.fragments.LineFragment; @@ -111,16 +111,16 @@ public class TextPatchBuilder { continue; } - final String beforeContent = beforeRevision.getContentAsString(); + final DiffString beforeContent = DiffString.createNullable(beforeRevision.getContentAsString()); if (beforeContent == null) { throw new VcsException("Failed to fetch old content for changed file " + beforeRevision.getPath().getPath()); } - final String afterContent = afterRevision.getContentAsString(); + final DiffString afterContent = DiffString.createNullable(afterRevision.getContentAsString()); if (afterContent == null) { throw new VcsException("Failed to fetch new content for changed file " + afterRevision.getPath().getPath()); } - String[] beforeLines = tokenize(beforeContent); - String[] afterLines = tokenize(afterContent); + DiffString[] beforeLines = tokenize(beforeContent); + DiffString[] afterLines = tokenize(afterContent); DiffFragment[] woFormattingBlocks; DiffFragment[] step1lineFragments; @@ -164,10 +164,10 @@ public class TextPatchBuilder { checkCanceled(); for(int i=contextStart1; i<fragment.getStartingLine1(); i++) { - addLineToHunk(hunk, beforeLines [i], PatchLine.Type.CONTEXT); + addLineToHunk(hunk, beforeLines[i], PatchLine.Type.CONTEXT); } for(int i=fragment.getStartingLine1(); i<fragment.getStartingLine1()+fragment.getModifiedLines1(); i++) { - addLineToHunk(hunk, beforeLines [i], PatchLine.Type.REMOVE); + addLineToHunk(hunk, beforeLines[i], PatchLine.Type.REMOVE); } for(int i=fragment.getStartingLine2(); i<fragment.getStartingLine2()+fragment.getModifiedLines2(); i++) { addLineToHunk(hunk, afterLines[i], PatchLine.Type.ADD); @@ -175,14 +175,14 @@ public class TextPatchBuilder { contextStart1 = fragment.getStartingLine1()+fragment.getModifiedLines1(); } for(int i=contextStart1; i<contextEnd1; i++) { - addLineToHunk(hunk, beforeLines [i], PatchLine.Type.CONTEXT); + addLineToHunk(hunk, beforeLines[i], PatchLine.Type.CONTEXT); } } } checkPathEndLine(patch, c.getAfter()); } else if (! beforeRevision.getPath().equals(afterRevision.getPath())) { - final TextFilePatch movedPatch = buildMovedFile(myBasePath, beforeRevision, afterRevision, beforeLines); + final TextFilePatch movedPatch = buildMovedFile(myBasePath, beforeRevision, afterRevision); checkPathEndLine(movedPatch, c.getAfter()); result.add(movedPatch); } @@ -205,8 +205,9 @@ public class TextPatchBuilder { } } - private static String[] tokenize(String text) { - return text.length() == 0 ? new String[]{text} : new LineTokenizer(text).execute(); + @NotNull + private static DiffString[] tokenize(@NotNull DiffString text) { + return text.length() == 0 ? new DiffString[]{text} : text.tokenize(); } private FilePatch buildBinaryPatch(final String basePath, @@ -221,20 +222,20 @@ public class TextPatchBuilder { return patch; } - private static void addLineToHunk(final PatchHunk hunk, final String line, final PatchLine.Type type) { + private static void addLineToHunk(@NotNull final PatchHunk hunk, @NotNull final DiffString line, final PatchLine.Type type) { final PatchLine patchLine; - if (!line.endsWith("\n")) { - patchLine = new PatchLine(type, line); + if (!line.endsWith('\n')) { + patchLine = new PatchLine(type, line.toString()); patchLine.setSuppressNewLine(true); } else { - patchLine = new PatchLine(type, line.substring(0, line.length()-1)); + patchLine = new PatchLine(type, line.substring(0, line.length() - 1).toString()); } hunk.addLine(patchLine); } private TextFilePatch buildMovedFile(final String basePath, final AirContentRevision beforeRevision, - final AirContentRevision afterRevision, final String[] lines) throws VcsException { + final AirContentRevision afterRevision) throws VcsException { final TextFilePatch result = buildPatchHeading(basePath, beforeRevision, afterRevision); final PatchHunk hunk = new PatchHunk(0, 0, 0, 0); result.addHunk(hunk); @@ -242,14 +243,14 @@ public class TextPatchBuilder { } private TextFilePatch buildAddedFile(final String basePath, final AirContentRevision afterRevision) throws VcsException { - final String content = afterRevision.getContentAsString(); + final DiffString content = DiffString.createNullable(afterRevision.getContentAsString()); if (content == null) { throw new VcsException("Failed to fetch content for added file " + afterRevision.getPath().getPath()); } - String[] lines = tokenize(content); + DiffString[] lines = tokenize(content); TextFilePatch result = buildPatchHeading(basePath, afterRevision, afterRevision); PatchHunk hunk = new PatchHunk(-1, -1, 0, lines.length); - for(String line: lines) { + for (DiffString line : lines) { checkCanceled(); addLineToHunk(hunk, line, PatchLine.Type.ADD); } @@ -258,14 +259,14 @@ public class TextPatchBuilder { } private TextFilePatch buildDeletedFile(String basePath, AirContentRevision beforeRevision) throws VcsException { - final String content = beforeRevision.getContentAsString(); + final DiffString content = DiffString.createNullable(beforeRevision.getContentAsString()); if (content == null) { throw new VcsException("Failed to fetch old content for deleted file " + beforeRevision.getPath().getPath()); } - String[] lines = tokenize(content); + DiffString[] lines = tokenize(content); TextFilePatch result = buildPatchHeading(basePath, beforeRevision, beforeRevision); PatchHunk hunk = new PatchHunk(0, lines.length, -1, -1); - for(String line: lines) { + for (DiffString line : lines) { checkCanceled(); addLineToHunk(hunk, line, PatchLine.Type.REMOVE); } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/vfs/AbstractVcsVirtualFile.java b/platform/vcs-api/src/com/intellij/openapi/vcs/vfs/AbstractVcsVirtualFile.java index 94b7e923fa79..a28564df1722 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/vfs/AbstractVcsVirtualFile.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/vfs/AbstractVcsVirtualFile.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. @@ -44,20 +44,25 @@ public abstract class AbstractVcsVirtualFile extends VirtualFile { myParent = null; } + @Override @NotNull public VirtualFileSystem getFileSystem() { return myFileSystem; } + @Override + @NotNull public String getPath() { return myPath; } + @Override @NotNull public String getName() { return myName; } + @Override public String getPresentableName() { if (myRevision == null) return myName; @@ -65,43 +70,53 @@ public abstract class AbstractVcsVirtualFile extends VirtualFile { return myName + " (" + myRevision + ")"; } + @Override public boolean isWritable() { return false; } + @Override public boolean isValid() { return true; } + @Override public VirtualFile getParent() { return myParent; } + @Override public VirtualFile[] getChildren() { return null; } + @Override public InputStream getInputStream() throws IOException { return VfsUtilCore.byteStreamSkippingBOM(contentsToByteArray(), this); } + @Override @NotNull public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) throws IOException { throw new RuntimeException(VcsFileSystem.COULD_NOT_IMPLEMENT_MESSAGE); } + @Override @NotNull public abstract byte[] contentsToByteArray() throws IOException; + @Override public long getModificationStamp() { return myModificationStamp; } + @Override public long getTimeStamp() { return myModificationStamp; } + @Override public long getLength() { try { return contentsToByteArray().length; @@ -110,6 +125,7 @@ public abstract class AbstractVcsVirtualFile extends VirtualFile { } } + @Override public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) { if (postRunnable != null) postRunnable.run(); @@ -123,6 +139,7 @@ public abstract class AbstractVcsVirtualFile extends VirtualFile { myProcessingBeforeContentsChange = true; try { ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override public void run() { ((VcsFileSystem)getFileSystem()).fireBeforeContentsChange(this, AbstractVcsVirtualFile.this); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java index 5b95283e1b30..2f3788ae509c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java @@ -146,7 +146,7 @@ public class FragmentedDiffRequestFromChange { comparisonPolicy = ComparisonPolicy.DEFAULT; } final TextCompareProcessor processor = new TextCompareProcessor(comparisonPolicy); - final ArrayList<LineFragment> lineFragments = processor.process(myOldDocument.getText(), myDocument.getText()); + final List<LineFragment> lineFragments = processor.process(myOldDocument.getText(), myDocument.getText()); myRanges = new ArrayList<BeforeAfter<TextRange>>(lineFragments.size()); for (LineFragment lineFragment : lineFragments) { if (!lineFragment.isEqual()) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java index 0f941a3a9c21..24884b4a101c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.ex; import com.intellij.codeInsight.hint.EditorFragmentComponent; import com.intellij.codeInsight.hint.HintManagerImpl; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diff.DiffColors; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -165,9 +166,6 @@ public class LineStatusTrackerDrawing { group.add(new ShowLineStatusRangeDiffAction(tracker, range, editor)); group.add(new CopyLineStatusRangeAction(tracker, range)); - @SuppressWarnings("unchecked") - final List<AnAction> actionList = (List<AnAction>)editorComponent.getClientProperty(AnAction.ourClientProperty); - final JComponent toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, group, true).getComponent(); final Color background = ((EditorEx)editor).getBackgroundColor(); @@ -218,6 +216,7 @@ public class LineStatusTrackerDrawing { EditorFactory.getInstance().releaseEditor(uEditor); } + final List<AnAction> actionList = ActionUtil.getActions(editorComponent); final LightweightHint lightweightHint = new LightweightHint(component); HintListener closeListener = new HintListener() { public void hintHidden(final EventObject event) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/VcsHistoryUtil.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/VcsHistoryUtil.java index 7711dd3ac394..e51a2a5f1abb 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/VcsHistoryUtil.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/VcsHistoryUtil.java @@ -38,6 +38,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.openapi.vfs.encoding.EncodingProjectManager; +import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent; import com.intellij.util.WaitForProgressToShow; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -121,7 +122,7 @@ public class VcsHistoryUtil { diffData.setContents(createContent(project, content1, revision1, doc, charset, fileType, filePath.getPath()), createContent(project, content2, revision2, doc, charset, fileType, filePath.getPath())); } else { - diffData.setContents(new FileContent(project, f1.get()), new FileContent(project, f2.get())); + diffData.setContents(createFileContent(project, f1.get(), revision1), createFileContent(project, f2.get(), revision2)); } WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() { public void run() { @@ -188,13 +189,22 @@ public class VcsHistoryUtil { private static DiffContent createContent(@NotNull Project project, byte[] content1, VcsFileRevision revision, Document doc, Charset charset, FileType fileType, String filePath) { if (isCurrent(revision) && (doc != null)) { return new DocumentContent(project, doc); } + if (isEmpty(revision)) { return SimpleContent.createEmpty(); } return new BinaryContent(project, content1, charset, fileType, filePath); } + private static DiffContent createFileContent(@NotNull Project project, VirtualFile file, VcsFileRevision revision) { + if (isEmpty(revision)) { return SimpleContent.createEmpty(); } + return new FileContent(project, file); + } + private static boolean isCurrent(VcsFileRevision revision) { return revision instanceof CurrentRevision; } + private static boolean isEmpty(VcsFileRevision revision) { + return revision == null || VcsFileRevision.NULL.equals(revision); + } /** * Shows difference between two revisions of a file in a diff tool. diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java index 26a26725fd90..a3a520376909 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.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. @@ -79,12 +79,12 @@ class VcsLogHashMap implements Disposable { private static class MyHashKeyDescriptor implements KeyDescriptor<Hash> { @Override - public void save(DataOutput out, Hash value) throws IOException { + public void save(@NotNull DataOutput out, Hash value) throws IOException { out.writeUTF(value.asString()); } @Override - public Hash read(DataInput in) throws IOException { + public Hash read(@NotNull DataInput in) throws IOException { return HashImpl.build(in.readUTF()); } diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java index 6a116d23387a..4f205e3f2eed 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java @@ -23,6 +23,8 @@ import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.xdebugger.breakpoints.XBreakpointHandler; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; +import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.frame.XValueMarkerProvider; import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; import com.intellij.xdebugger.ui.XDebugTabLayouter; @@ -226,4 +228,9 @@ public abstract class XDebugProcess { return false; } + @Nullable + public XDebuggerEvaluator getEvaluator() { + XStackFrame frame = getSession().getCurrentStackFrame(); + return frame == null ? null : frame.getEvaluator(); + } } diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java index 534545847f42..be71aac98d1e 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java @@ -83,6 +83,7 @@ public interface XDebugSession extends AbstractDebuggerSession { /** * @deprecated use {@link #setCurrentStackFrame(com.intellij.xdebugger.frame.XExecutionStack, com.intellij.xdebugger.frame.XStackFrame)} instead */ + @SuppressWarnings("UnusedDeclaration") void setCurrentStackFrame(@NotNull XStackFrame frame); /** diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java index a6b07b3e4173..676fb3f32826 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java @@ -100,4 +100,11 @@ public abstract class XLineBreakpointType<P extends XBreakpointProperties> exten public Icon getTemporaryIcon() { return AllIcons.Debugger.Db_temporary_breakpoint; } + + /** + * Higher priority wins if several types available for the line(s) + */ + public int getPriority() { + return 0; + } } diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java b/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java index 1cf23c566d0b..7130b7747c25 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java @@ -115,7 +115,7 @@ public abstract class XDebuggerEvaluator { * @param offset offset * @param sideEffectsAllowed if this parameter is false, the expression should not have any side effects when evaluated * (such expressions are evaluated in quick popups) - * @return pair of text range of expression (to display as link) and actual expression to evaluate (optional, could be null) + * @return pair of text range of expression (to highlight as link) and actual expression to evaluate (optional, could be null) */ @Nullable public Pair<TextRange, String> getExpressionAtOffset(@NotNull Project project, @NotNull Document document, int offset, boolean sideEffectsAllowed) { diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XStackFrame.java b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XStackFrame.java index eaa642037d95..ba5d5f37b1cc 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XStackFrame.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XStackFrame.java @@ -22,6 +22,7 @@ import com.intellij.ui.SimpleTextAttributes; import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -63,7 +64,7 @@ public abstract class XStackFrame extends XValueContainer { * Customize presentation of the stack frame in frames list * @param component component */ - public void customizePresentation(ColoredTextContainer component) { + public void customizePresentation(@NotNull ColoredTextContainer component) { XSourcePosition position = getSourcePosition(); if (position != null) { component.append(position.getFile().getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/stepping/PsiBackedSmartStepIntoVariant.java b/platform/xdebugger-api/src/com/intellij/xdebugger/stepping/PsiBackedSmartStepIntoVariant.java index f2728161ef13..d17f8e01271d 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/stepping/PsiBackedSmartStepIntoVariant.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/stepping/PsiBackedSmartStepIntoVariant.java @@ -36,6 +36,7 @@ public class PsiBackedSmartStepIntoVariant<T extends PsiNamedElement & Navigatio assert myPresentation != null: "Invalid presentation:" + myElement; } + @Override public String getText() { String location = myPresentation.getLocationString(); return myPresentation.getPresentableText() + (location != null ? " " + location: ""); @@ -46,6 +47,7 @@ public class PsiBackedSmartStepIntoVariant<T extends PsiNamedElement & Navigatio return myPresentation.getIcon(false); } + @NotNull public T getElement() { return myElement; } diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/stepping/XSmartStepIntoHandler.java b/platform/xdebugger-api/src/com/intellij/xdebugger/stepping/XSmartStepIntoHandler.java index 46dcaa236651..56b098de99f0 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/stepping/XSmartStepIntoHandler.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/stepping/XSmartStepIntoHandler.java @@ -40,7 +40,7 @@ public abstract class XSmartStepIntoHandler<Variant extends XSmartStepIntoVarian * when <code>variant</code> function/method is reached * @param variant selected variant */ - public abstract void startStepInto(Variant variant); + public abstract void startStepInto(@NotNull Variant variant); /** * @return title for popup which will be shown to select method/function diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java index 42bee651e742..82c052240673 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java @@ -15,11 +15,15 @@ */ package com.intellij.xdebugger.impl; +import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.xdebugger.AbstractDebuggerSession; -import com.intellij.xdebugger.impl.actions.*; +import com.intellij.xdebugger.impl.actions.DebuggerActionHandler; +import com.intellij.xdebugger.impl.actions.DebuggerToggleActionHandler; +import com.intellij.xdebugger.impl.actions.EditBreakpointActionHandler; +import com.intellij.xdebugger.impl.actions.MarkObjectActionHandler; import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointPanelProvider; import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler; import com.intellij.xdebugger.impl.settings.DebuggerSettingsPanelProvider; @@ -32,6 +36,19 @@ import org.jetbrains.annotations.Nullable; public abstract class DebuggerSupport { private static final ExtensionPointName<DebuggerSupport> EXTENSION_POINT = ExtensionPointName.create("com.intellij.xdebugger.debuggerSupport"); + protected static final class DisabledActionHandler extends DebuggerActionHandler { + public static final DisabledActionHandler INSTANCE = new DisabledActionHandler(); + + @Override + public void perform(@NotNull Project project, AnActionEvent event) { + } + + @Override + public boolean isEnabled(@NotNull Project project, AnActionEvent event) { + return false; + } + } + @NotNull public static DebuggerSupport[] getDebuggerSupports() { return Extensions.getExtensions(EXTENSION_POINT); @@ -95,6 +112,10 @@ public abstract class DebuggerSupport { @NotNull public abstract DebuggerActionHandler getAddToWatchesActionHandler(); + public DebuggerActionHandler getEvaluateInConsoleActionHandler() { + return DisabledActionHandler.INSTANCE; + } + @NotNull public abstract DebuggerToggleActionHandler getMuteBreakpointsHandler(); @@ -116,6 +137,6 @@ public abstract class DebuggerSupport { return support; } } - return null; + throw new IllegalStateException(); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index ea407a2cfcd4..337f6fe28a89 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -51,6 +51,7 @@ import com.intellij.openapi.wm.ToolWindowId; import com.intellij.ui.AppUIUtil; import com.intellij.util.EventDispatcher; import com.intellij.util.SmartList; +import com.intellij.util.containers.SmartHashSet; import com.intellij.util.ui.UIUtil; import com.intellij.xdebugger.*; import com.intellij.xdebugger.breakpoints.*; @@ -67,6 +68,7 @@ import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; import com.intellij.xdebugger.stepping.XSmartStepIntoVariant; +import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -86,8 +88,8 @@ public class XDebugSessionImpl implements XDebugSession { false); private XDebugProcess myDebugProcess; private final Map<XBreakpoint<?>, CustomizedBreakpointPresentation> myRegisteredBreakpoints = - new HashMap<XBreakpoint<?>, CustomizedBreakpointPresentation>(); - private final Set<XBreakpoint<?>> myInactiveSlaveBreakpoints = new HashSet<XBreakpoint<?>>(); + new THashMap<XBreakpoint<?>, CustomizedBreakpointPresentation>(); + private final Set<XBreakpoint<?>> myInactiveSlaveBreakpoints = new SmartHashSet<XBreakpoint<?>>(); private boolean myBreakpointsMuted; private boolean myBreakpointsDisabled; private final XDebuggerManagerImpl myDebuggerManager; @@ -329,6 +331,7 @@ public class XDebugSessionImpl implements XDebugSession { return myValueMarkers; } + @SuppressWarnings("unchecked") //need to compile under 1.8, please do not remove before checking private static XBreakpointType getBreakpointTypeClass(final XBreakpointHandler handler) { return XDebuggerUtil.getInstance().findBreakpointType(handler.getBreakpointTypeClass()); } @@ -351,12 +354,9 @@ public class XDebugSessionImpl implements XDebugSession { handler.registerBreakpoint(b); } if (!register) { - boolean removed = false; + boolean removed; synchronized (myRegisteredBreakpoints) { - if (myRegisteredBreakpoints.containsKey(b)) { - myRegisteredBreakpoints.remove(b); - removed = true; - } + removed = myRegisteredBreakpoints.remove(b) != null; } if (removed) { handler.unregisterBreakpoint(b, temporary); @@ -780,7 +780,7 @@ public class XDebugSessionImpl implements XDebugSession { myBreakpointsDisabled = false; new ReadAction() { @Override - protected void run(final Result result) { + protected void run(@NotNull Result result) { processAllBreakpoints(true, false); } }.execute(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerSupport.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerSupport.java index c56f2c723261..fbfe184a5f3f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerSupport.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerSupport.java @@ -50,11 +50,14 @@ public class XDebuggerSupport extends DebuggerSupport { private final XDebuggerEvaluateActionHandler myEvaluateHandler; private final XQuickEvaluateHandler myQuickEvaluateHandler; private final XDebuggerSettingsPanelProviderImpl mySettingsPanelProvider; + private final XAddToWatchesFromEditorActionHandler myAddToWatchesActionHandler; + private final DebuggerActionHandler myEvaluateInConsoleActionHandler = new XEvaluateInConsoleFromEditorActionHandler(); + private final DebuggerToggleActionHandler myMuteBreakpointsHandler; private final DebuggerActionHandler mySmartStepIntoHandler; private final XMarkObjectActionHandler myMarkObjectActionHandler; - private final EditBreakpointActionHandler myEditBreakpointActoinHandler; + private final EditBreakpointActionHandler myEditBreakpointActionHandler; public XDebuggerSupport() { myBreakpointPanelProvider = new XBreakpointPanelProvider(); @@ -62,26 +65,31 @@ public class XDebuggerSupport extends DebuggerSupport { myToggleTemporaryLineBreakpointActionHandler = new XToggleLineBreakpointActionHandler(true); myAddToWatchesActionHandler = new XAddToWatchesFromEditorActionHandler(); myStepOverHandler = new XDebuggerSuspendedActionHandler() { + @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { session.stepOver(false); } }; myStepIntoHandler = new XDebuggerSuspendedActionHandler() { + @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { session.stepInto(); } }; myStepOutHandler = new XDebuggerSuspendedActionHandler() { + @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { session.stepOut(); } }; myForceStepOverHandler = new XDebuggerSuspendedActionHandler() { + @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { session.stepOver(true); } }; myForceStepIntoHandler = new XDebuggerSuspendedActionHandler() { + @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { session.forceStepInto(); } @@ -90,16 +98,19 @@ public class XDebuggerSupport extends DebuggerSupport { myRunToCursorHandler = new XDebuggerRunToCursorActionHandler(false); myForceRunToCursor = new XDebuggerRunToCursorActionHandler(true); myResumeHandler = new XDebuggerActionHandler() { + @Override protected boolean isEnabled(@NotNull final XDebugSession session, final DataContext dataContext) { return session.isPaused(); } + @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { session.resume(); } }; myPauseHandler = new XDebuggerPauseActionHandler(); myShowExecutionPointHandler = new XDebuggerSuspendedActionHandler() { + @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { session.showExecutionPoint(); } @@ -109,64 +120,76 @@ public class XDebuggerSupport extends DebuggerSupport { myQuickEvaluateHandler = new XQuickEvaluateHandler(); mySettingsPanelProvider = new XDebuggerSettingsPanelProviderImpl(); myMarkObjectActionHandler = new XMarkObjectActionHandler(); - myEditBreakpointActoinHandler = new XDebuggerEditBreakpointActionHandler(); + myEditBreakpointActionHandler = new XDebuggerEditBreakpointActionHandler(); } + @Override @NotNull public BreakpointPanelProvider<?> getBreakpointPanelProvider() { return myBreakpointPanelProvider; } + @Override @NotNull public DebuggerActionHandler getStepOverHandler() { return myStepOverHandler; } + @Override @NotNull public DebuggerActionHandler getStepIntoHandler() { return myStepIntoHandler; } + @Override @NotNull public DebuggerActionHandler getSmartStepIntoHandler() { return mySmartStepIntoHandler; } + @Override @NotNull public DebuggerActionHandler getStepOutHandler() { return myStepOutHandler; } + @Override @NotNull public DebuggerActionHandler getForceStepOverHandler() { return myForceStepOverHandler; } + @Override @NotNull public DebuggerActionHandler getForceStepIntoHandler() { return myForceStepIntoHandler; } + @Override @NotNull public DebuggerActionHandler getRunToCursorHandler() { return myRunToCursorHandler; } + @Override @NotNull public DebuggerActionHandler getForceRunToCursorHandler() { return myForceRunToCursor; } + @Override @NotNull public DebuggerActionHandler getResumeActionHandler() { return myResumeHandler; } + @Override @NotNull public DebuggerActionHandler getPauseHandler() { return myPauseHandler; } + @Override @NotNull public DebuggerActionHandler getToggleLineBreakpointHandler() { return myToggleLineBreakpointActionHandler; @@ -178,16 +201,19 @@ public class XDebuggerSupport extends DebuggerSupport { return myToggleTemporaryLineBreakpointActionHandler; } + @Override @NotNull public DebuggerActionHandler getShowExecutionPointHandler() { return myShowExecutionPointHandler; } + @Override @NotNull public DebuggerActionHandler getEvaluateHandler() { return myEvaluateHandler; } + @Override @NotNull public QuickEvaluateHandler getQuickEvaluateHandler() { return myQuickEvaluateHandler; @@ -200,6 +226,13 @@ public class XDebuggerSupport extends DebuggerSupport { } @NotNull + @Override + public DebuggerActionHandler getEvaluateInConsoleActionHandler() { + return myEvaluateInConsoleActionHandler; + } + + @Override + @NotNull public DebuggerToggleActionHandler getMuteBreakpointsHandler() { return myMuteBreakpointsHandler; } @@ -218,12 +251,12 @@ public class XDebuggerSupport extends DebuggerSupport { @NotNull @Override public EditBreakpointActionHandler getEditBreakpointAction() { - return myEditBreakpointActoinHandler; + return myEditBreakpointActionHandler; } + @Override @NotNull public DebuggerSettingsPanelProvider getSettingsPanelProvider() { return mySettingsPanelProvider; } - } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java index 76a360f748ab..191b8f2b1cfb 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java @@ -75,12 +75,15 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { @Override public void toggleLineBreakpoint(@NotNull final Project project, @NotNull final VirtualFile file, final int line, boolean temporary) { + XLineBreakpointType<?> typeWinner = null; for (XLineBreakpointType<?> type : getLineBreakpointTypes()) { - if (type.canPutAt(file, line, project)) { - toggleLineBreakpoint(project, type, file, line, temporary); - return; + if (type.canPutAt(file, line, project) && (typeWinner == null || type.getPriority() > typeWinner.getPriority())) { + typeWinner = type; } } + if (typeWinner != null) { + toggleLineBreakpoint(project, typeWinner, file, line, temporary); + } } @Override @@ -222,34 +225,34 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { @Override public void iterateLine(@NotNull Project project, @NotNull Document document, int line, @NotNull Processor<PsiElement> processor) { PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); - if (file == null) return; + if (file == null) { + return; + } int lineStart; int lineEnd; - try { lineStart = document.getLineStartOffset(line); lineEnd = document.getLineEndOffset(line); } - catch (IndexOutOfBoundsException e) { + catch (IndexOutOfBoundsException ignored) { return; } PsiElement element; - - int off = lineStart; - while (off < lineEnd) { - element = file.findElementAt(off); + int offset = lineStart; + while (offset < lineEnd) { + element = file.findElementAt(offset); if (element != null) { if (!processor.process(element)) { return; } else { - off = element.getTextRange().getEndOffset(); + offset = element.getTextRange().getEndOffset(); } } else { - off++; + offset++; } } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/AddToWatchesAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/AddToWatchesAction.java index 33bfc5a33e02..c93496be2699 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/AddToWatchesAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/AddToWatchesAction.java @@ -18,10 +18,7 @@ package com.intellij.xdebugger.impl.actions; import com.intellij.xdebugger.impl.DebuggerSupport; import org.jetbrains.annotations.NotNull; -/** - * @author nik - */ -public class AddToWatchesAction extends XDebuggerActionBase { +final class AddToWatchesAction extends XDebuggerActionBase { public AddToWatchesAction() { super(true); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EvaluateAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EvaluateAction.java index 39e594902ef8..ea17644e53f0 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EvaluateAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EvaluateAction.java @@ -15,17 +15,18 @@ */ package com.intellij.xdebugger.impl.actions; -import org.jetbrains.annotations.NotNull; import com.intellij.xdebugger.impl.DebuggerSupport; +import org.jetbrains.annotations.NotNull; /** * @author nik */ -public class EvaluateAction extends XDebuggerActionBase { +final class EvaluateAction extends XDebuggerActionBase { public EvaluateAction() { super(true); } + @Override @NotNull protected DebuggerActionHandler getHandler(@NotNull final DebuggerSupport debuggerSupport) { return debuggerSupport.getEvaluateHandler(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EvaluateInConsoleAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EvaluateInConsoleAction.java new file mode 100644 index 000000000000..ebfbb94ed5da --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EvaluateInConsoleAction.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2010 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.xdebugger.impl.actions; + +import com.intellij.xdebugger.impl.DebuggerSupport; +import org.jetbrains.annotations.NotNull; + +final class EvaluateInConsoleAction extends XDebuggerActionBase { + public EvaluateInConsoleAction() { + super(true); + } + + @NotNull + @Override + protected DebuggerActionHandler getHandler(@NotNull DebuggerSupport debuggerSupport) { + return debuggerSupport.getEvaluateInConsoleActionHandler(); + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/QuickEvaluateAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/QuickEvaluateAction.java index 25e1b012eba0..be54d591d378 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/QuickEvaluateAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/QuickEvaluateAction.java @@ -40,6 +40,7 @@ public class QuickEvaluateAction extends XDebuggerActionBase { super(true); } + @Override @NotNull protected DebuggerActionHandler getHandler(@NotNull final DebuggerSupport debuggerSupport) { return new QuickEvaluateHandlerWrapper(debuggerSupport.getQuickEvaluateHandler()); @@ -52,6 +53,7 @@ public class QuickEvaluateAction extends XDebuggerActionBase { myHandler = handler; } + @Override public void perform(@NotNull final Project project, final AnActionEvent event) { Editor editor = event.getData(CommonDataKeys.EDITOR); if (editor != null) { @@ -61,11 +63,16 @@ public class QuickEvaluateAction extends XDebuggerActionBase { } } + @Override public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) { - if (!myHandler.isEnabled(project)) return false; + if (!myHandler.isEnabled(project)) { + return false; + } Editor editor = event.getData(CommonDataKeys.EDITOR); - if (editor == null) return false; + if (editor == null) { + return false; + } InputEvent inputEvent = event.getInputEvent(); if (inputEvent instanceof MouseEvent && inputEvent.isAltDown()) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/ResumeAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/ResumeAction.java index c669ec2b3298..011c41b209e1 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/ResumeAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/ResumeAction.java @@ -19,7 +19,7 @@ import com.intellij.execution.actions.ChooseDebugConfigurationPopupAction; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.xdebugger.AbstractDebuggerSession; import com.intellij.xdebugger.impl.DebuggerSupport; @@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull; /** * @author nik */ -public class ResumeAction extends XDebuggerActionBase { +public class ResumeAction extends XDebuggerActionBase implements DumbAware { @Override protected boolean isEnabled(AnActionEvent e) { Project project = e.getData(CommonDataKeys.PROJECT); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/ShowExecutionPointAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/ShowExecutionPointAction.java index a00e2618c5a5..12def64e36ef 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/ShowExecutionPointAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/ShowExecutionPointAction.java @@ -15,13 +15,14 @@ */ package com.intellij.xdebugger.impl.actions; -import org.jetbrains.annotations.NotNull; import com.intellij.xdebugger.impl.DebuggerSupport; +import org.jetbrains.annotations.NotNull; /** * @author nik */ public class ShowExecutionPointAction extends XDebuggerActionBase { + @Override @NotNull protected DebuggerActionHandler getHandler(@NotNull final DebuggerSupport debuggerSupport) { return debuggerSupport.getShowExecutionPointHandler(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/SmartStepIntoAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/SmartStepIntoAction.java index f886f1f1b80a..adc2589b645c 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/SmartStepIntoAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/SmartStepIntoAction.java @@ -15,13 +15,14 @@ */ package com.intellij.xdebugger.impl.actions; -import org.jetbrains.annotations.NotNull; import com.intellij.xdebugger.impl.DebuggerSupport; +import org.jetbrains.annotations.NotNull; /** * @author nik */ -public class SmartStepIntoAction extends XDebuggerActionBase { +final class SmartStepIntoAction extends XDebuggerActionBase { + @Override @NotNull protected DebuggerActionHandler getHandler(@NotNull final DebuggerSupport debuggerSupport) { return debuggerSupport.getSmartStepIntoHandler(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerActionBase.java index 8ed04300d973..5e3a6c100646 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerActionBase.java @@ -39,8 +39,7 @@ public abstract class XDebuggerActionBase extends AnAction implements AnAction.T Presentation presentation = event.getPresentation(); boolean hidden = isHidden(event); if (hidden) { - presentation.setEnabled(false); - presentation.setVisible(false); + presentation.setEnabledAndVisible(false); return; } @@ -100,7 +99,7 @@ public abstract class XDebuggerActionBase extends AnAction implements AnAction.T } protected boolean isHidden(AnActionEvent event) { - final Project project = event.getData(CommonDataKeys.PROJECT); + final Project project = event.getProject(); if (project != null) { for (DebuggerSupport support : DebuggerSupport.getDebuggerSupports()) { if (!getHandler(support).isHidden(project, event)) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerSuspendedActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerSuspendedActionHandler.java index 70ecabddcdea..0137fac87ac2 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerSuspendedActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerSuspendedActionHandler.java @@ -15,16 +15,16 @@ */ package com.intellij.xdebugger.impl.actions; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.impl.actions.handlers.XDebuggerActionHandler; -import com.intellij.openapi.actionSystem.DataContext; import org.jetbrains.annotations.NotNull; /** * @author nik */ public abstract class XDebuggerSuspendedActionHandler extends XDebuggerActionHandler { - + @Override protected boolean isEnabled(final @NotNull XDebugSession session, final DataContext dataContext) { return session.isSuspended(); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XAddToWatchesFromEditorActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XAddToWatchesFromEditorActionHandler.java index 3b52fa58bf7b..b1aac452c60f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XAddToWatchesFromEditorActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XAddToWatchesFromEditorActionHandler.java @@ -20,7 +20,7 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.text.StringUtil; import com.intellij.xdebugger.XDebugSession; -import com.intellij.xdebugger.frame.XStackFrame; +import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; import com.intellij.xdebugger.impl.XDebugSessionImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,17 +35,17 @@ public class XAddToWatchesFromEditorActionHandler extends XDebuggerActionHandler } @Nullable - private static String getTextToEvaluate(DataContext dataContext, XDebugSession session) { + protected static String getTextToEvaluate(DataContext dataContext, XDebugSession session) { final Editor editor = CommonDataKeys.EDITOR.getData(dataContext); if (editor == null) { return null; } String text = editor.getSelectionModel().getSelectedText(); - if (text == null && session.isSuspended()) { - final XStackFrame stackFrame = session.getCurrentStackFrame(); - if (stackFrame != null) { - text = XDebuggerEvaluateActionHandler.getExpressionText(stackFrame.getEvaluator(), editor.getProject(), editor); + if (text == null) { + XDebuggerEvaluator evaluator = session.getDebugProcess().getEvaluator(); + if (evaluator != null) { + text = XDebuggerEvaluateActionHandler.getExpressionText(evaluator, editor.getProject(), editor); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerActionHandler.java index 3ac02a62dbdb..fa079b3ff707 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerActionHandler.java @@ -15,19 +15,19 @@ */ package com.intellij.xdebugger.impl.actions.handlers; -import com.intellij.xdebugger.impl.actions.DebuggerActionHandler; -import com.intellij.xdebugger.XDebuggerManager; -import com.intellij.xdebugger.XDebugSession; -import com.intellij.openapi.project.Project; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.project.Project; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XDebuggerManager; +import com.intellij.xdebugger.impl.actions.DebuggerActionHandler; import org.jetbrains.annotations.NotNull; /** * @author nik */ public abstract class XDebuggerActionHandler extends DebuggerActionHandler { - + @Override public void perform(@NotNull final Project project, final AnActionEvent event) { XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); if (session != null) { @@ -35,6 +35,7 @@ public abstract class XDebuggerActionHandler extends DebuggerActionHandler { } } + @Override public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) { XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); return session != null && isEnabled(session, event.getDataContext()); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java index d892acaf0f44..1a24b3074216 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java @@ -28,7 +28,6 @@ import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.frame.XValue; -import com.intellij.xdebugger.impl.actions.XDebuggerSuspendedActionHandler; import com.intellij.xdebugger.impl.evaluate.XDebuggerEvaluationDialog; import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase; import org.jetbrains.annotations.NotNull; @@ -37,14 +36,15 @@ import org.jetbrains.annotations.Nullable; /** * @author nik */ -public class XDebuggerEvaluateActionHandler extends XDebuggerSuspendedActionHandler { +public class XDebuggerEvaluateActionHandler extends XDebuggerActionHandler { @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { XDebuggerEditorsProvider editorsProvider = session.getDebugProcess().getEditorsProvider(); XStackFrame stackFrame = session.getCurrentStackFrame(); - if (stackFrame == null) return; - final XDebuggerEvaluator evaluator = stackFrame.getEvaluator(); - if (evaluator == null) return; + final XDebuggerEvaluator evaluator = session.getDebugProcess().getEvaluator(); + if (evaluator == null) { + return; + } @Nullable Editor editor = CommonDataKeys.EDITOR.getData(dataContext); @@ -64,7 +64,7 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerSuspendedActionHand text = value.getEvaluationExpression(); } } - new XDebuggerEvaluationDialog(session, editorsProvider, evaluator, StringUtil.notNullize(text), stackFrame.getSourcePosition()).show(); + new XDebuggerEvaluationDialog(session, editorsProvider, evaluator, StringUtil.notNullize(text), stackFrame == null ? null : stackFrame.getSourcePosition()).show(); } @Nullable @@ -86,11 +86,6 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerSuspendedActionHand @Override protected boolean isEnabled(final @NotNull XDebugSession session, final DataContext dataContext) { - if (!super.isEnabled(session, dataContext)) { - return false; - } - - XStackFrame stackFrame = session.getCurrentStackFrame(); - return stackFrame != null && stackFrame.getEvaluator() != null; + return session.getDebugProcess().getEvaluator() != null; } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerSmartStepIntoHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerSmartStepIntoHandler.java index 4a933b794aac..6d09b8fd3128 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerSmartStepIntoHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerSmartStepIntoHandler.java @@ -15,21 +15,21 @@ */ package com.intellij.xdebugger.impl.actions.handlers; -import org.jetbrains.annotations.NotNull; -import com.intellij.xdebugger.XDebugSession; -import com.intellij.xdebugger.XSourcePosition; -import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; -import com.intellij.xdebugger.stepping.XSmartStepIntoVariant; -import com.intellij.xdebugger.impl.actions.XDebuggerSuspendedActionHandler; -import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.ui.awt.RelativePoint; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.impl.actions.XDebuggerSuspendedActionHandler; +import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; +import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; +import com.intellij.xdebugger.stepping.XSmartStepIntoVariant; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.util.List; @@ -39,10 +39,12 @@ import java.util.List; */ public class XDebuggerSmartStepIntoHandler extends XDebuggerSuspendedActionHandler { + @Override protected boolean isEnabled(@NotNull XDebugSession session, DataContext dataContext) { return super.isEnabled(session, dataContext) && session.getDebugProcess().getSmartStepIntoHandler() != null; } + @Override protected void perform(@NotNull XDebugSession session, DataContext dataContext) { final XSmartStepIntoHandler<?> handler = session.getDebugProcess().getSmartStepIntoHandler(); final XSourcePosition position = session.getCurrentPosition(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XEvaluateInConsoleFromEditorActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XEvaluateInConsoleFromEditorActionHandler.java new file mode 100644 index 000000000000..fb5f3d7d8b66 --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XEvaluateInConsoleFromEditorActionHandler.java @@ -0,0 +1,86 @@ +package com.intellij.xdebugger.impl.actions.handlers; + +import com.intellij.execution.console.ConsoleExecuteAction; +import com.intellij.execution.console.LanguageConsoleView; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class XEvaluateInConsoleFromEditorActionHandler extends XAddToWatchesFromEditorActionHandler { + @Override + protected boolean isEnabled(@NotNull XDebugSession session, DataContext dataContext) { + return super.isEnabled(session, dataContext) && getConsoleExecuteAction(session) != null; + } + + @Nullable + private static ConsoleExecuteAction getConsoleExecuteAction(@NotNull XDebugSession session) { + return getConsoleExecuteAction(session.getConsoleView()); + } + + @Nullable + public static ConsoleExecuteAction getConsoleExecuteAction(@Nullable ConsoleView consoleView) { + if (!(consoleView instanceof LanguageConsoleView)) { + return null; + } + + List<AnAction> actions = ActionUtil.getActions(((LanguageConsoleView)consoleView).getConsole().getConsoleEditor().getComponent()); + ConsoleExecuteAction action = ContainerUtil.findInstance(actions, ConsoleExecuteAction.class); + return action == null || !action.isEnabled() ? null : action; + } + + @Override + protected void perform(@NotNull XDebugSession session, DataContext dataContext) { + Editor editor = CommonDataKeys.EDITOR.getData(dataContext); + if (editor == null || !(editor instanceof EditorEx)) { + return; + } + + int selectionStart = editor.getSelectionModel().getSelectionStart(); + int selectionEnd = editor.getSelectionModel().getSelectionEnd(); + String text; + TextRange range; + if (selectionStart != selectionEnd) { + range = new TextRange(selectionStart, selectionEnd); + text = editor.getDocument().getText(range); + } + else { + XDebuggerEvaluator evaluator = session.getDebugProcess().getEvaluator(); + if (evaluator != null) { + Pair<TextRange, String> expressionInfo = evaluator.getExpressionAtOffset(session.getProject(), editor.getDocument(), selectionStart, true); + if (expressionInfo == null) { + return; + } + + // todo check - is it wrong in case of not-null expressionInfo.second - copied (to console history document) text (text range) could be not correct statement? + range = expressionInfo.first; + text = XDebuggerEvaluateActionHandler.getExpressionText(expressionInfo, editor.getDocument()); + } + else { + return; + } + } + + if (StringUtil.isEmptyOrSpaces(text)) { + return; + } + + ConsoleExecuteAction action = getConsoleExecuteAction(session); + if (action != null) { + action.execute(range, text, (EditorEx)editor); + } + } +}
\ No newline at end of file diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XToggleLineBreakpointActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XToggleLineBreakpointActionHandler.java index 03ae0184ec22..e100741566ac 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XToggleLineBreakpointActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XToggleLineBreakpointActionHandler.java @@ -15,10 +15,12 @@ */ package com.intellij.xdebugger.impl.actions.handlers; +import com.intellij.codeInsight.folding.impl.FoldingUtil; import com.intellij.codeInsight.folding.impl.actions.ExpandRegionAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.FoldRegion; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.xdebugger.XDebuggerUtil; @@ -63,20 +65,42 @@ public class XToggleLineBreakpointActionHandler extends DebuggerActionHandler { XSourcePosition position = XDebuggerUtilImpl.getCaretPosition(project, event.getDataContext()); if (position == null) return; - ExpandRegionAction.expandRegionAtCaret(project, event.getData(CommonDataKeys.EDITOR)); + Editor editor = event.getData(CommonDataKeys.EDITOR); + + // for folded text check each line and find out type with the biggest priority + int lineStart = position.getLine(); + int linesEnd = lineStart; + FoldRegion region = FoldingUtil.findFoldRegionStartingAtLine(editor, lineStart); + if (region != null && !region.isExpanded()) { + linesEnd = region.getDocument().getLineNumber(region.getEndOffset()); + } - int line = position.getLine(); VirtualFile file = position.getFile(); final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); - for (XLineBreakpointType<?> type : XDebuggerUtil.getInstance().getLineBreakpointTypes()) { - final XLineBreakpoint<? extends XBreakpointProperties> breakpoint = breakpointManager.findBreakpointAtLine(type, file, line); - if (breakpoint != null && myTemporary && !breakpoint.isTemporary()) { - breakpoint.setTemporary(true); - } else if (type.canPutAt(file, line, project) || breakpoint != null) { - XDebuggerUtil.getInstance().toggleLineBreakpoint(project, type, file, line, myTemporary); - return; + XLineBreakpointType<?>[] lineTypes = XDebuggerUtil.getInstance().getLineBreakpointTypes(); + XLineBreakpointType<?> typeWinner = null; + int lineWinner = -1; + for (int line = lineStart; line <= linesEnd; line++) { + for (XLineBreakpointType<?> type : lineTypes) { + final XLineBreakpoint<? extends XBreakpointProperties> breakpoint = breakpointManager.findBreakpointAtLine(type, file, line); + if (breakpoint != null && myTemporary && !breakpoint.isTemporary()) { + breakpoint.setTemporary(true); + } else if (type.canPutAt(file, line, project) || breakpoint != null) { + if (typeWinner == null || type.getPriority() > typeWinner.getPriority()) { + typeWinner = type; + lineWinner = line; + } + } } } - } + if (typeWinner != null) { + XDebuggerUtil.getInstance().toggleLineBreakpoint(project, typeWinner, file, lineWinner, myTemporary); + } + + ExpandRegionAction.expandRegionAtCaret(project, editor); + if (editor != null && lineStart != lineWinner) { + editor.getCaretModel().moveToOffset(editor.getDocument().getLineStartOffset(lineWinner)); + } + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointState.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointState.java index 530fb995aae9..5f95c73ed635 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointState.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointState.java @@ -15,10 +15,7 @@ */ package com.intellij.xdebugger.impl.breakpoints; -import com.intellij.util.xmlb.annotations.Attribute; -import com.intellij.util.xmlb.annotations.Property; -import com.intellij.util.xmlb.annotations.Tag; -import com.intellij.util.xmlb.annotations.Transient; +import com.intellij.util.xmlb.annotations.*; import com.intellij.xdebugger.breakpoints.SuspendPolicy; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; @@ -36,8 +33,8 @@ public class BreakpointState<B extends XBreakpoint<P>, P extends XBreakpointProp private Element myPropertiesElement; private SuspendPolicy mySuspendPolicy = SuspendPolicy.ALL; private boolean myLogMessage; - private String myLogExpression; - private String myCondition; + private LogExpression myLogExpression; + private Condition myCondition; private XBreakpointDependencyState myDependencyState; private long myTimeStamp; @@ -104,22 +101,52 @@ public class BreakpointState<B extends XBreakpoint<P>, P extends XBreakpointProp myLogMessage = logMessage; } - @Tag("log-expression") + @Transient public String getLogExpression() { + return myLogExpression != null ? myLogExpression.myExpression : null; + } + + public void setLogExpression(String expression) { + if (expression != null) { + myLogExpression = new LogExpression(); + myLogExpression.myExpression = expression; + } + else { + myLogExpression = null; + } + } + + @Property(surroundWithTag = false) + public LogExpression getLogExpressionObject() { return myLogExpression; } - public void setLogExpression(final String logExpression) { - myLogExpression = logExpression; + public void setLogExpressionObject(final LogExpression logExpression) { + setLogExpression(logExpression.myOldExpression != null ? logExpression.myOldExpression : logExpression.myExpression); } - @Tag("condition") + @Transient public String getCondition() { + return myCondition != null ? myCondition.myExpression : null; + } + + public void setCondition(String condition) { + if (condition != null) { + myCondition = new Condition(); + myCondition.myExpression = condition; + } + else { + myCondition = null; + } + } + + @Property(surroundWithTag = false) + public Condition getConditionObject() { return myCondition; } - public void setCondition(final String condition) { - myCondition = condition; + public void setConditionObject(final Condition condition) { + setCondition(condition.myOldExpression != null ? condition.myOldExpression : condition.myExpression); } @Property(surroundWithTag = false) @@ -142,4 +169,24 @@ public class BreakpointState<B extends XBreakpoint<P>, P extends XBreakpointProp public void setTimeStamp(long timeStamp) { myTimeStamp = timeStamp; } + + void applyDefaults(BreakpointState state) { + state.mySuspendPolicy = mySuspendPolicy; + } + + @Tag("condition") + public static class Condition { + @Attribute("expression") + public String myExpression; + @Text + public String myOldExpression; + } + + @Tag("log-expression") + public static class LogExpression { + @Attribute("expression") + public String myExpression; + @Text + public String myOldExpression; + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointsFavoriteListProvider.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointsFavoriteListProvider.java index 03adc64be2ad..a2a76c84bc18 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointsFavoriteListProvider.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointsFavoriteListProvider.java @@ -52,7 +52,6 @@ public class BreakpointsFavoriteListProvider extends AbstractFavoritesListProvid private final List<BreakpointPanelProvider> myBreakpointPanelProviders; private final BreakpointItemsTreeController myTreeController; private final List<XBreakpointGroupingRule> myRulesAvailable = new ArrayList<XBreakpointGroupingRule>(); - private final BreakpointsSimpleTree myTree; private Set<XBreakpointGroupingRule> myRulesEnabled = new TreeSet<XBreakpointGroupingRule>(new Comparator<XBreakpointGroupingRule>() { @Override @@ -66,8 +65,7 @@ public class BreakpointsFavoriteListProvider extends AbstractFavoritesListProvid super(project, "Breakpoints"); myBreakpointPanelProviders = XBreakpointUtil.collectPanelProviders(); myTreeController = new BreakpointItemsTreeController(myRulesAvailable); - myTree = new BreakpointsSimpleTree(myProject, myTreeController); - myTreeController.setTreeView(myTree); + myTreeController.setTreeView(new BreakpointsSimpleTree(myProject, myTreeController)); updateChildren(); for (final BreakpointPanelProvider provider : myBreakpointPanelProviders) { provider.addListener(this, myProject, myProject); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointItem.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointItem.java index aed4f88cf2a0..f7dff8b23760 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointItem.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointItem.java @@ -86,7 +86,10 @@ class XBreakpointItem extends BreakpointItem { public void doUpdateDetailView(DetailView panel, boolean editorOnly) { Project project = ((XBreakpointBase)myBreakpoint).getProject(); //saveState(); - myPropertiesPanel = null; + if (myPropertiesPanel != null) { + myPropertiesPanel.dispose(); + myPropertiesPanel = null; + } if (!editorOnly) { myPropertiesPanel = new XLightBreakpointPropertiesPanel<XBreakpoint<?>>(project, getManager(), myBreakpoint, true); @@ -178,4 +181,10 @@ class XBreakpointItem extends BreakpointItem { return 0; } } + + public void dispose() { + if (myPropertiesPanel != null) { + myPropertiesPanel.dispose(); + } + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java index eb183f9145e9..233c473fc952 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java @@ -50,6 +50,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta public static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTER = new SkipDefaultValuesSerializationFilters(); private final MultiValuesMap<XBreakpointType, XBreakpointBase<?,?,?>> myBreakpoints = new MultiValuesMap<XBreakpointType, XBreakpointBase<?,?,?>>(true); private final Map<XBreakpointType, XBreakpointBase<?,?,?>> myDefaultBreakpoints = new LinkedHashMap<XBreakpointType, XBreakpointBase<?, ?, ?>>(); + private final Map<XBreakpointType, BreakpointState<?,?,?>> myBreakpointsDefaults = new LinkedHashMap<XBreakpointType, BreakpointState<?, ?, ?>>(); private final Set<XBreakpointBase<?,?,?>> myAllBreakpoints = new HashSet<XBreakpointBase<?, ?, ?>>(); private final Map<XBreakpointType, EventDispatcher<XBreakpointListener>> myDispatchers = new HashMap<XBreakpointType, EventDispatcher<XBreakpointListener>>(); private XBreakpointsDialogState myBreakpointsDialogSettings; @@ -67,14 +68,16 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta myAllBreakpointsDispatcher = EventDispatcher.create(XBreakpointListener.class); myDependentBreakpointManager = new XDependentBreakpointManager(this); myLineBreakpointManager = new XLineBreakpointManager(project, myDependentBreakpointManager, startupManager); - if (!project.isDefault() && !ApplicationManager.getApplication().isUnitTestMode()) { - HttpVirtualFileListener httpVirtualFileListener = new HttpVirtualFileListener() { - @Override - public void fileDownloaded(@NotNull final VirtualFile file) { - updateBreakpointInFile(file); - } - }; - HttpFileSystem.getInstance().addFileListener(httpVirtualFileListener, project); + if (!project.isDefault()) { + if (!ApplicationManager.getApplication().isUnitTestMode()) { + HttpVirtualFileListener httpVirtualFileListener = new HttpVirtualFileListener() { + @Override + public void fileDownloaded(@NotNull final VirtualFile file) { + updateBreakpointInFile(file); + } + }; + HttpFileSystem.getInstance().addFileListener(httpVirtualFileListener, project); + } for (XBreakpointType<?, ?> type : XBreakpointUtil.getBreakpointTypes()) { addDefaultBreakpoint(type); } @@ -127,6 +130,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta BreakpointState<?,T,?> state = new BreakpointState<XBreakpoint<T>,T,XBreakpointType<XBreakpoint<T>,T>>(enabled, type.getId(), defaultBreakpoint ? 0 : myTime++); + getBreakpointDefaults(type).applyDefaults(state); return new XBreakpointBase<XBreakpoint<T>,T, BreakpointState<?,T,?>>(type, this, properties, state); } @@ -213,8 +217,11 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta @Nullable final T properties, boolean temporary) { ApplicationManager.getApplication().assertWriteAccessAllowed(); + LineBreakpointState<T> state = new LineBreakpointState<T>(true, type.getId(), fileUrl, line, temporary, + myTime++); + getBreakpointDefaults(type).applyDefaults(state); XLineBreakpointImpl<T> breakpoint = new XLineBreakpointImpl<T>(type, this, properties, - new LineBreakpointState<T>(true, type.getId(), fileUrl, line, temporary, myTime++)); + state); addBreakpoint(breakpoint, false, true); return breakpoint; } @@ -353,6 +360,12 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta state.getBreakpoints().add(breakpoint.getState()); } + for (Map.Entry<XBreakpointType, BreakpointState<?,?,?>> entry : myBreakpointsDefaults.entrySet()) { + if (statesAreDifferent(entry.getValue(), createBreakpointDefaults(entry.getKey()))) { + state.getBreakpointsDefaults().add(entry.getValue()); + } + } + state.setBreakpointsDialogProperties(myBreakpointsDialogSettings); state.setTime(myTime); return state; @@ -366,9 +379,13 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta } BreakpointState defaultState = ((XBreakpointBase)defaultBreakpoint).getState(); - Element defaultElement = XmlSerializer.serialize(defaultState, SERIALIZATION_FILTER); - Element currentElement = XmlSerializer.serialize(state, SERIALIZATION_FILTER); - return !JDOMUtil.areElementsEqual(defaultElement, currentElement); + return statesAreDifferent(state, defaultState); + } + + private static boolean statesAreDifferent(BreakpointState state1, BreakpointState state2) { + Element elem1 = XmlSerializer.serialize(state1, SERIALIZATION_FILTER); + Element elem2 = XmlSerializer.serialize(state2, SERIALIZATION_FILTER); + return !JDOMUtil.areElementsEqual(elem1, elem2); } @Override @@ -377,6 +394,8 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta myAllBreakpoints.clear(); myDefaultBreakpoints.clear(); + myBreakpointsDefaults.clear(); + for (BreakpointState breakpointState : state.getDefaultBreakpoints()) { loadBreakpoint(breakpointState, true); } @@ -392,6 +411,12 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta for (BreakpointState breakpointState : state.getBreakpoints()) { loadBreakpoint(breakpointState, false); } + + for (BreakpointState defaults : state.getBreakpointsDefaults()) { + XBreakpointType<?,?> type = XBreakpointUtil.findType(defaults.getTypeId()); + myBreakpointsDefaults.put(type, defaults); + } + myDependentBreakpointManager.loadState(); myLineBreakpointManager.updateBreakpointsUI(); myTime = state.getTime(); @@ -439,11 +464,26 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta return breakpointState.createBreakpoint(type, this); } + public BreakpointState getBreakpointDefaults(XBreakpointType type) { + BreakpointState defaultState = myBreakpointsDefaults.get(type); + if (defaultState == null) { + defaultState = createBreakpointDefaults(type); + myBreakpointsDefaults.put(type, defaultState); + } + return defaultState; + } + + private static BreakpointState createBreakpointDefaults(XBreakpointType type) { + BreakpointState state = new BreakpointState(); + state.setTypeId(type.getId()); + return state; + } @Tag("breakpoint-manager") public static class BreakpointManagerState { private List<BreakpointState> myDefaultBreakpoints = new ArrayList<BreakpointState>(); private List<BreakpointState> myBreakpoints = new ArrayList<BreakpointState>(); + private List<BreakpointState> myBreakpointsDefaults = new ArrayList<BreakpointState>(); private XBreakpointsDialogState myBreakpointsDialogProperties; private long myTime; @@ -461,6 +501,13 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta return myBreakpoints; } + @Tag("breakpoints-defaults") + @AbstractCollection(surroundWithTag = false, + elementTypes = {BreakpointState.class, LineBreakpointState.class}) + public List<BreakpointState> getBreakpointsDefaults() { + return myBreakpointsDefaults; + } + @Tag("breakpoints-dialog") public XBreakpointsDialogState getBreakpointsDialogProperties() { return myBreakpointsDialogProperties; @@ -475,6 +522,10 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta myDefaultBreakpoints = defaultBreakpoints; } + public void setBreakpointsDefaults(List<BreakpointState> breakpointsDefaults) { + myBreakpointsDefaults = breakpointsDefaults; + } + public void setBreakpointsDialogProperties(XBreakpointsDialogState breakpointsDialogProperties) { myBreakpointsDialogProperties = breakpointsDialogProperties; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java index 6aae02242ec4..07214a6f7671 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java @@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.MarkupModelEx; +import com.intellij.openapi.editor.ex.RangeHighlighterEx; import com.intellij.openapi.editor.impl.DocumentMarkupModel; import com.intellij.openapi.editor.markup.GutterDraggableObject; import com.intellij.openapi.editor.markup.RangeHighlighter; @@ -54,7 +55,7 @@ import java.util.List; * @author nik */ public class XLineBreakpointImpl<P extends XBreakpointProperties> extends XBreakpointBase<XLineBreakpoint<P>, P, LineBreakpointState<P>> implements XLineBreakpoint<P> { - @Nullable private RangeHighlighter myHighlighter; + @Nullable private RangeHighlighterEx myHighlighter; private final XLineBreakpointType<P> myType; private XSourcePosition mySourcePosition; private boolean myDisposed; @@ -86,25 +87,37 @@ public class XLineBreakpointImpl<P extends XBreakpointProperties> extends XBreak EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme(); TextAttributes attributes = scheme.getAttributes(DebuggerColors.BREAKPOINT_ATTRIBUTES); - RangeHighlighter highlighter = myHighlighter; - if (highlighter != null && highlighter.isValid() && document.getLineNumber(highlighter.getStartOffset()) != getLine()) { + RangeHighlighterEx highlighter = myHighlighter; + if (highlighter != null && (!highlighter.isValid() || document.getLineNumber(highlighter.getStartOffset()) != getLine())) { highlighter.dispose(); myHighlighter = null; highlighter = null; } + MarkupModelEx markupModel; if (highlighter == null) { - MarkupModelEx markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, getProject(), true); + markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, getProject(), true); highlighter = markupModel.addPersistentLineHighlighter(getLine(), DebuggerColors.BREAKPOINT_HIGHLIGHTER_LAYER, attributes); - if (highlighter != null) { - highlighter.setGutterIconRenderer(createGutterIconRenderer()); - highlighter.putUserData(DebuggerColors.BREAKPOINT_HIGHLIGHTER_KEY, Boolean.TRUE); - myHighlighter = highlighter; + if (highlighter == null) { + return; } + + highlighter.setGutterIconRenderer(createGutterIconRenderer()); + highlighter.putUserData(DebuggerColors.BREAKPOINT_HIGHLIGHTER_KEY, Boolean.TRUE); + myHighlighter = highlighter; + } + else { + markupModel = null; } - if (highlighter != null) { - updateIcon(); + updateIcon(); + + if (markupModel == null) { + markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, getProject(), false); + if (markupModel != null) { + // renderersChanged false — we don't change gutter size + markupModel.fireAttributesChanged(highlighter, false); + } } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java index e438b857a6ba..67b0ece2f5ac 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java @@ -167,7 +167,7 @@ public class BreakpointsDialog extends DialogWrapper { @NotNull @Override protected Action[] createActions() { - return new Action[]{getOKAction()}; + return new Action[]{getOKAction(), getHelpAction()}; } private class ToggleBreakpointGroupingRuleEnabledAction extends ToggleActionButton { @@ -380,6 +380,12 @@ public class BreakpointsDialog extends DialogWrapper { } } + @Nullable + @Override + protected String getHelpId() { + return "reference.dialogs.breakpoints"; + } + private void saveCurrentItem() { ItemWrapper item = myDetailController.getSelectedItem(); if (item instanceof BreakpointItem) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/DefaultConditionComboBoxPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/DefaultConditionComboBoxPanel.java new file mode 100644 index 000000000000..9cee406625a7 --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/DefaultConditionComboBoxPanel.java @@ -0,0 +1,61 @@ +/* + * 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. + * 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.xdebugger.impl.breakpoints.ui; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import com.intellij.xdebugger.impl.ui.XDebuggerExpressionComboBox; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author egor + */ +public class DefaultConditionComboBoxPanel<B extends XBreakpoint<?>> extends XBreakpointCustomPropertiesPanel<B> { + private XDebuggerExpressionComboBox myConditionComboBox; + + public DefaultConditionComboBoxPanel(Project project, + XDebuggerEditorsProvider debuggerEditorsProvider, + String historyId, + XSourcePosition sourcePosition) { + myConditionComboBox = new XDebuggerExpressionComboBox(project, debuggerEditorsProvider, historyId, sourcePosition); + } + + @NotNull + @Override + public JComponent getComponent() { + return myConditionComboBox.getComponent(); + } + + @Override + public void saveTo(@NotNull B breakpoint) { + final String condition = StringUtil.nullize(myConditionComboBox.getText(), true); + breakpoint.setCondition(condition); + if (condition != null) { + myConditionComboBox.saveTextInHistory(); + } + } + + @Override + public void loadFrom(@NotNull B breakpoint) { + myConditionComboBox.setText(StringUtil.notNullize(breakpoint.getCondition())); + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/DefaultLogExpressionComboBoxPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/DefaultLogExpressionComboBoxPanel.java new file mode 100644 index 000000000000..a4ff954c7375 --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/DefaultLogExpressionComboBoxPanel.java @@ -0,0 +1,59 @@ +/* + * 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. + * 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.xdebugger.impl.breakpoints.ui; + +import com.intellij.openapi.project.Project; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import com.intellij.xdebugger.impl.ui.XDebuggerExpressionComboBox; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author egor + */ +public class DefaultLogExpressionComboBoxPanel<B extends XBreakpoint<?>> extends XBreakpointCustomPropertiesPanel<B> { + private XDebuggerExpressionComboBox myLogExpressionComboBox; + + public DefaultLogExpressionComboBoxPanel(Project project, + XDebuggerEditorsProvider debuggerEditorsProvider, + String historyId, + XSourcePosition sourcePosition) { + myLogExpressionComboBox = new XDebuggerExpressionComboBox(project, debuggerEditorsProvider, historyId, sourcePosition); + } + + @NotNull + @Override + public JComponent getComponent() { + return myLogExpressionComboBox.getComponent(); + } + + @Override + public void saveTo(@NotNull B breakpoint) { + String logExpression = myLogExpressionComboBox.getComponent().isEnabled() ? myLogExpressionComboBox.getText() : null; + breakpoint.setLogExpression(logExpression); + myLogExpressionComboBox.saveTextInHistory(); + } + + @Override + public void loadFrom(@NotNull B breakpoint) { + String logExpression = breakpoint.getLogExpression(); + myLogExpressionComboBox.setText(logExpression != null ? logExpression : ""); + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XBreakpointActionsPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XBreakpointActionsPanel.java index 26049ac69e51..2ccff41e5c7e 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XBreakpointActionsPanel.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XBreakpointActionsPanel.java @@ -19,9 +19,9 @@ import com.intellij.openapi.project.Project; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XBreakpointManager; import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; -import com.intellij.xdebugger.impl.ui.XDebuggerExpressionComboBox; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +44,7 @@ public class XBreakpointActionsPanel<B extends XBreakpoint<?>> extends XBreakpoi private JPanel myContentPane; private JPanel myMainPanel; private JCheckBox myTemporaryCheckBox; - private XDebuggerExpressionComboBox myLogExpressionComboBox; + XBreakpointCustomPropertiesPanel<B> logExpressionPanel; public void init(Project project, XBreakpointManager breakpointManager, @NotNull B breakpoint, @Nullable XDebuggerEditorsProvider debuggerEditorsProvider) { init(project, breakpointManager, breakpoint); @@ -55,10 +55,18 @@ public class XBreakpointActionsPanel<B extends XBreakpoint<?>> extends XBreakpoi } }; - myLogExpressionComboBox = new XDebuggerExpressionComboBox(project, debuggerEditorsProvider, "breakpointLogExpression", myBreakpoint.getSourcePosition()); - JComponent logExpressionComponent = myLogExpressionComboBox.getComponent(); + if (debuggerEditorsProvider instanceof XDebuggerComboBoxProvider) { + logExpressionPanel = ((XDebuggerComboBoxProvider<B>)debuggerEditorsProvider).createLogExpressionComboBoxPanel( + project, debuggerEditorsProvider, "breakpointCondition", myBreakpoint.getSourcePosition()); + } + else { + logExpressionPanel = + new DefaultLogExpressionComboBoxPanel<B>(project, debuggerEditorsProvider, "breakpointCondition", myBreakpoint.getSourcePosition()); + } + + JComponent logExpressionComponent = logExpressionPanel.getComponent(); myLogExpressionPanel.add(logExpressionComponent, BorderLayout.CENTER); - myLogExpressionComboBox.setEnabled(false); + logExpressionComponent.setEnabled(false); myTemporaryCheckBox.setVisible(breakpoint instanceof XLineBreakpoint); myLogExpressionCheckBox.addActionListener(listener); DebuggerUIUtil.focusEditorOnCheck(myLogExpressionCheckBox, logExpressionComponent); @@ -81,8 +89,8 @@ public class XBreakpointActionsPanel<B extends XBreakpoint<?>> extends XBreakpoi } private void onCheckboxChanged() { - if (myLogExpressionComboBox != null) { - myLogExpressionComboBox.setEnabled(myLogExpressionCheckBox.isSelected()); + if (logExpressionPanel != null) { + logExpressionPanel.getComponent().setEnabled(myLogExpressionCheckBox.isSelected()); } } @@ -94,10 +102,9 @@ public class XBreakpointActionsPanel<B extends XBreakpoint<?>> extends XBreakpoi myTemporaryCheckBox.setSelected(((XLineBreakpoint)myBreakpoint).isTemporary()); } - if (myLogExpressionComboBox != null) { - String logExpression = myBreakpoint.getLogExpression(); - myLogExpressionCheckBox.setSelected(logExpression != null); - myLogExpressionComboBox.setText(logExpression != null ? logExpression : ""); + if (logExpressionPanel != null) { + myLogExpressionCheckBox.setSelected(myBreakpoint.getLogExpression() != null); + logExpressionPanel.loadFrom(myBreakpoint); } onCheckboxChanged(); } @@ -110,11 +117,14 @@ public class XBreakpointActionsPanel<B extends XBreakpoint<?>> extends XBreakpoi ((XLineBreakpoint)myBreakpoint).setTemporary(myTemporaryCheckBox.isSelected()); } - if (myLogExpressionComboBox != null) { - String logExpression = myLogExpressionCheckBox.isSelected() ? myLogExpressionComboBox.getText() : null; - myBreakpoint.setLogExpression(logExpression); - myLogExpressionComboBox.saveTextInHistory(); + if (logExpressionPanel != null) { + logExpressionPanel.saveTo(myBreakpoint); } + } + public void dispose() { + if (logExpressionPanel != null) { + logExpressionPanel.dispose(); + } } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XDebuggerComboBoxProvider.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XDebuggerComboBoxProvider.java new file mode 100644 index 000000000000..fd5391146657 --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XDebuggerComboBoxProvider.java @@ -0,0 +1,37 @@ +/* + * 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. + * 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.xdebugger.impl.breakpoints.ui; + +import com.intellij.openapi.project.Project; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; + +/** + * @author egor + */ +public interface XDebuggerComboBoxProvider<B extends XBreakpoint<?>> { + XBreakpointCustomPropertiesPanel<B> createConditionComboBoxPanel(Project project, + XDebuggerEditorsProvider debuggerEditorsProvider, + String historyId, + XSourcePosition sourcePosition); + + XBreakpointCustomPropertiesPanel<B> createLogExpressionComboBoxPanel(Project project, + XDebuggerEditorsProvider debuggerEditorsProvider, + String historyId, + XSourcePosition sourcePosition); +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java index bc6d5e4395ae..7c910835dd63 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java @@ -16,7 +16,6 @@ package com.intellij.xdebugger.impl.breakpoints.ui; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.popup.util.DetailView; import com.intellij.xdebugger.breakpoints.XBreakpoint; @@ -26,7 +25,6 @@ import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.impl.breakpoints.XBreakpointBase; import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil; -import com.intellij.xdebugger.impl.ui.XDebuggerExpressionComboBox; import javax.swing.*; import java.awt.*; @@ -83,8 +81,6 @@ public class XLightBreakpointPropertiesPanel<B extends XBreakpoint<?>> implement private List<XBreakpointPropertiesSubPanel<B>> mySubPanels = new ArrayList<XBreakpointPropertiesSubPanel<B>>(); - private XDebuggerExpressionComboBox myConditionComboBox; - private B myBreakpoint; public void setDetailView(DetailView detailView) { @@ -106,10 +102,25 @@ public class XLightBreakpointPropertiesPanel<B extends XBreakpoint<?>> implement myActionsPanel.init(project, breakpointManager, breakpoint, debuggerEditorsProvider); mySubPanels.add(myActionsPanel); + myCustomPanels = new ArrayList<XBreakpointCustomPropertiesPanel<B>>(); if (debuggerEditorsProvider != null) { - myConditionComboBox = new XDebuggerExpressionComboBox(project, debuggerEditorsProvider, "breakpointCondition", myBreakpoint.getSourcePosition()); - JComponent conditionComponent = myConditionComboBox.getComponent(); - myConditionExpressionPanel.add(conditionComponent, BorderLayout.CENTER); + final XBreakpointCustomPropertiesPanel<B> conditionPanel; + if (debuggerEditorsProvider instanceof XDebuggerComboBoxProvider) { + conditionPanel = ((XDebuggerComboBoxProvider<B>)debuggerEditorsProvider).createConditionComboBoxPanel( + project, debuggerEditorsProvider, "breakpointCondition", myBreakpoint.getSourcePosition()); + } + else { + conditionPanel = + new DefaultConditionComboBoxPanel<B>(project, debuggerEditorsProvider, "breakpointCondition", myBreakpoint.getSourcePosition()); + } + myConditionExpressionPanel.add(conditionPanel.getComponent(), BorderLayout.CENTER); + myCustomPanels.add(conditionPanel); + myMainPanel.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent event) { + IdeFocusManager.findInstance().requestFocus(conditionPanel.getComponent(), false); + } + }); } else { myConditionPanel.setVisible(false); } @@ -121,7 +132,6 @@ public class XLightBreakpointPropertiesPanel<B extends XBreakpoint<?>> implement } } - myCustomPanels = new ArrayList<XBreakpointCustomPropertiesPanel<B>>(); XBreakpointCustomPropertiesPanel<B> customPropertiesPanel = breakpointType.createCustomPropertiesPanel(); if (customPropertiesPanel != null) { myCustomPropertiesPanelWrapper.add(customPropertiesPanel.getComponent(), BorderLayout.CENTER); @@ -140,14 +150,6 @@ public class XLightBreakpointPropertiesPanel<B extends XBreakpoint<?>> implement myCustomPanels.add(customRightConditionPanel); } - myMainPanel.addFocusListener(new FocusAdapter() { - @Override - public void focusGained(FocusEvent event) { - if (myConditionComboBox != null) { - IdeFocusManager.findInstance().requestFocus(myConditionComboBox.getComponent(), false); - } - } - }); myEnabledCheckbox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { @@ -161,14 +163,6 @@ public class XLightBreakpointPropertiesPanel<B extends XBreakpoint<?>> implement panel.saveProperties(); } - if (myConditionComboBox != null) { - final String condition = StringUtil.nullize(myConditionComboBox.getText(), true); - myBreakpoint.setCondition(condition); - if (condition != null) { - myConditionComboBox.saveTextInHistory(); - } - } - for (XBreakpointCustomPropertiesPanel<B> customPanel : myCustomPanels) { customPanel.saveTo(myBreakpoint); } @@ -183,10 +177,6 @@ public class XLightBreakpointPropertiesPanel<B extends XBreakpoint<?>> implement panel.loadProperties(); } - if (myConditionComboBox != null) { - myConditionComboBox.setText(StringUtil.notNullize(myBreakpoint.getCondition())); - } - for (XBreakpointCustomPropertiesPanel<B> customPanel : myCustomPanels) { customPanel.loadFrom(myBreakpoint); } @@ -197,4 +187,11 @@ public class XLightBreakpointPropertiesPanel<B extends XBreakpoint<?>> implement public JPanel getMainPanel() { return myMainPanel; } + + public void dispose() { + myActionsPanel.dispose(); + for (XBreakpointCustomPropertiesPanel<B> panel : myCustomPanels) { + panel.dispose(); + } + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XSuspendPolicyPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XSuspendPolicyPanel.java index c46914fa06b8..b3dcd1302735 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XSuspendPolicyPanel.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XSuspendPolicyPanel.java @@ -15,11 +15,11 @@ */ package com.intellij.xdebugger.impl.breakpoints.ui; -import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.project.Project; import com.intellij.xdebugger.breakpoints.SuspendPolicy; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XBreakpointManager; +import com.intellij.xdebugger.impl.breakpoints.XBreakpointManagerImpl; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -72,7 +72,7 @@ public class XSuspendPolicyPanel<B extends XBreakpoint<?>> extends XBreakpointPr mySuspendPolicyGroup.add(mySuspendAll); mySuspendPolicyGroup.add(mySuspendThread); - updateSuspendPolicyFont(createSettingsKey()); + updateSuspendPolicyFont(); ItemListener suspendPolicyChangeListener = new ItemListener() { @Override @@ -89,9 +89,8 @@ public class XSuspendPolicyPanel<B extends XBreakpoint<?>> extends XBreakpointPr @Override public void actionPerformed(ActionEvent e) { SuspendPolicy suspendPolicy = getSelectedSuspendPolicy(); - String settingsKey = createSettingsKey(); - PropertiesComponent.getInstance().setValue(settingsKey, suspendPolicy.name()); - updateSuspendPolicyFont(settingsKey); + ((XBreakpointManagerImpl)myBreakpointManager).getBreakpointDefaults(myBreakpointType).setSuspendPolicy(suspendPolicy); + updateSuspendPolicyFont(); if (SuspendPolicy.THREAD == suspendPolicy) { mySuspendThread.requestFocus(); } @@ -104,20 +103,16 @@ public class XSuspendPolicyPanel<B extends XBreakpoint<?>> extends XBreakpointPr } private void updateMakeDefaultEnableState() { - myMakeDefaultButton.setEnabled(!getSelectedSuspendPolicy().name().equalsIgnoreCase(PropertiesComponent.getInstance().getValue(createSettingsKey(), SuspendPolicy.ALL.name()))); + myMakeDefaultButton.setEnabled(!getSelectedSuspendPolicy().equals(((XBreakpointManagerImpl)myBreakpointManager).getBreakpointDefaults(myBreakpointType).getSuspendPolicy())); } - private String createSettingsKey() { - return "debugger.suspend.policy-" + myBreakpointType.getId(); - } - - private void updateSuspendPolicyFont(String settingsKey) { - String defaultPolicy = PropertiesComponent.getInstance().getValue(settingsKey, SuspendPolicy.ALL.name()); + private void updateSuspendPolicyFont() { + SuspendPolicy defaultPolicy = ((XBreakpointManagerImpl)myBreakpointManager).getBreakpointDefaults(myBreakpointType).getSuspendPolicy(); Font font = mySuspendAll.getFont().deriveFont(Font.PLAIN); Font boldFont = font.deriveFont(Font.BOLD); - mySuspendAll.setFont(SuspendPolicy.ALL.name().equalsIgnoreCase(defaultPolicy) ? boldFont : font); - mySuspendThread.setFont(SuspendPolicy.THREAD.name().equalsIgnoreCase(defaultPolicy) ? boldFont : font); + mySuspendAll.setFont(SuspendPolicy.ALL.equals(defaultPolicy) ? boldFont : font); + mySuspendThread.setFont(SuspendPolicy.THREAD.equals(defaultPolicy) ? boldFont : font); } private void changeEnableState(boolean selected) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java index d00e27418edc..c0005393a8a4 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java @@ -17,6 +17,8 @@ package com.intellij.xdebugger.impl.breakpoints.ui.grouping; import com.intellij.util.ArrayUtil; import com.intellij.xdebugger.breakpoints.XBreakpointType; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.XLineBreakpointType; import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroup; import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil; import org.jetbrains.annotations.NotNull; @@ -49,6 +51,22 @@ public class XBreakpointTypeGroup extends XBreakpointGroup { @Override public int compareTo(XBreakpointGroup o) { if (o instanceof XBreakpointTypeGroup) { + if (((XBreakpointTypeGroup)o).myBreakpointType instanceof XLineBreakpointType) { + if (myBreakpointType instanceof XLineBreakpointType) { + int res = ((XLineBreakpointType)((XBreakpointTypeGroup)o).myBreakpointType).getPriority() - + ((XLineBreakpointType)myBreakpointType).getPriority(); + if (res != 0) { + return res; + } + } + else { + // line breakpoints should be on top + return 1; + } + } + else if (myBreakpointType instanceof XLineBreakpointType) { + return -1; + } return indexOfType(myBreakpointType) - indexOfType(((XBreakpointTypeGroup)o).getBreakpointType()); } return -o.compareTo(this); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/tree/BreakpointItemsTreeController.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/tree/BreakpointItemsTreeController.java index babdd0939ace..7c90280fc0f3 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/tree/BreakpointItemsTreeController.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/tree/BreakpointItemsTreeController.java @@ -43,7 +43,6 @@ public class BreakpointItemsTreeController implements BreakpointsCheckboxTree.De private final CheckedTreeNode myRoot; private final Map<BreakpointItem, BreakpointItemNode> myNodes = new HashMap<BreakpointItem, BreakpointItemNode>(); private List<XBreakpointGroupingRule> myGroupingRules; - private final Map<XBreakpointGroup, BreakpointsGroupNode> myGroupNodes = new HashMap<XBreakpointGroup, BreakpointsGroupNode>(); private final MultiValuesMap<XBreakpointGroupingRule, XBreakpointGroup> myGroups = new MultiValuesMap<XBreakpointGroupingRule, XBreakpointGroup>(); @@ -110,7 +109,6 @@ public class BreakpointItemsTreeController implements BreakpointsCheckboxTree.De final TreeState state = TreeState.createOn(myTreeView, myRoot); myRoot.removeAllChildren(); myNodes.clear(); - myGroupNodes.clear(); myGroups.clear(); for (BreakpointItem breakpoint : breakpoints) { BreakpointItemNode node = new BreakpointItemNode(breakpoint); @@ -130,53 +128,42 @@ public class BreakpointItemsTreeController implements BreakpointsCheckboxTree.De @NotNull private CheckedTreeNode getParentNode(final BreakpointItem breakpoint) { CheckedTreeNode parent = myRoot; - XBreakpointGroup parentGroup = null; for (int i = 0; i < myGroupingRules.size(); i++) { - XBreakpointGroup group = getGroup(parentGroup, breakpoint, myGroupingRules.get(i)); + Collection<XBreakpointGroup> existingGroups = getGroupNodes(parent); + XBreakpointGroup group = myGroupingRules.get(i).getGroup(breakpoint.getBreakpoint(), existingGroups); if (group != null) { parent = getOrCreateGroupNode(parent, group, i); - parentGroup = group; } } return parent; } - @Nullable - private XBreakpointGroup getGroup(XBreakpointGroup parentGroup, final BreakpointItem breakpoint, final XBreakpointGroupingRule groupingRule) { - //noinspection unchecked - Collection<XBreakpointGroup> groups = myGroups.get(groupingRule); - if (groups == null) { - groups = Collections.emptyList(); - } - - XBreakpointGroup group = groupingRule.getGroup(breakpoint.getBreakpoint(), filterByParent(parentGroup, groups)); - if (group != null) { - myGroups.put(groupingRule, group); - } - return group; - } - - private Collection<XBreakpointGroup> filterByParent(XBreakpointGroup parentGroup, Collection<XBreakpointGroup> groups) { - Collection<XBreakpointGroup> filtered = new ArrayList<XBreakpointGroup>(); - for (XBreakpointGroup group : groups) { - TreeNode parentNode = myGroupNodes.get(group).getParent(); - BreakpointsGroupNode parent = parentNode instanceof BreakpointsGroupNode ? (BreakpointsGroupNode)parentNode : null; - if ((parentGroup == null && parentNode == myRoot) || (parent != null && parent.getGroup() == parentGroup)) { - filtered.add(group); + private static Collection<XBreakpointGroup> getGroupNodes(CheckedTreeNode parent) { + Collection<XBreakpointGroup> nodes = new ArrayList<XBreakpointGroup>(); + Enumeration children = parent.children(); + while (children.hasMoreElements()) { + Object element = children.nextElement(); + if (element instanceof BreakpointsGroupNode) { + nodes.add(((BreakpointsGroupNode)element).getGroup()); } } - return filtered; + return nodes; } - private <G extends XBreakpointGroup> BreakpointsGroupNode<G> getOrCreateGroupNode(CheckedTreeNode parent, final G group, + private static BreakpointsGroupNode getOrCreateGroupNode(CheckedTreeNode parent, final XBreakpointGroup group, final int level) { - //noinspection unchecked - BreakpointsGroupNode<G> groupNode = (BreakpointsGroupNode<G>)myGroupNodes.get(group); - if (groupNode == null) { - groupNode = new BreakpointsGroupNode<G>(group, level); - myGroupNodes.put(group, groupNode); - parent.add(groupNode); + Enumeration children = parent.children(); + while (children.hasMoreElements()) { + Object element = children.nextElement(); + if (element instanceof BreakpointsGroupNode) { + XBreakpointGroup groupFound = ((BreakpointsGroupNode)element).getGroup(); + if (groupFound.equals(group)) { + return (BreakpointsGroupNode)element; + } + } } + BreakpointsGroupNode groupNode = new BreakpointsGroupNode<XBreakpointGroup>(group, level); + parent.add(groupNode); return groupNode; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java index 741b2878e8b2..4abf17312585 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java @@ -29,7 +29,6 @@ import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.evaluation.EvaluationMode; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; -import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.ui.XDebuggerEditorBase; @@ -38,6 +37,7 @@ import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreePanel; import com.intellij.xdebugger.impl.ui.tree.nodes.EvaluatingExpressionRootNode; import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -61,10 +61,10 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { private final boolean myIsCodeFragmentEvaluationSupported; public XDebuggerEvaluationDialog(@NotNull XDebugSession session, - final @NotNull XDebuggerEditorsProvider editorsProvider, + @NotNull XDebuggerEditorsProvider editorsProvider, @NotNull XDebuggerEvaluator evaluator, @NotNull String text, - final XSourcePosition sourcePosition) { + @Nullable XSourcePosition sourcePosition) { super(session.getProject(), true); mySession = session; myEditorsProvider = editorsProvider; @@ -212,8 +212,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { inputEditor.saveTextInHistory(); String expression = inputEditor.getText(); - XStackFrame frame = mySession.getCurrentStackFrame(); - XDebuggerEvaluator evaluator = frame == null ? null : frame.getEvaluator(); + XDebuggerEvaluator evaluator = mySession.getDebugProcess().getEvaluator(); if (evaluator == null) { evaluationCallback.errorOccurred(XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator")); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XQuickEvaluateHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XQuickEvaluateHandler.java index 8813e70d823b..81e94ff7a851 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XQuickEvaluateHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XQuickEvaluateHandler.java @@ -26,7 +26,6 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; -import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHint; import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler; import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType; @@ -44,11 +43,7 @@ public class XQuickEvaluateHandler extends QuickEvaluateHandler { @Override public boolean isEnabled(@NotNull final Project project) { XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); - if (session == null || !session.isSuspended()) { - return false; - } - XStackFrame stackFrame = session.getCurrentStackFrame(); - return stackFrame != null && stackFrame.getEvaluator() != null; + return session != null && session.getDebugProcess().getEvaluator() != null; } @Override @@ -58,11 +53,7 @@ public class XQuickEvaluateHandler extends QuickEvaluateHandler { return null; } - XStackFrame stackFrame = session.getCurrentStackFrame(); - if (stackFrame == null) { - return null; - } - final XDebuggerEvaluator evaluator = stackFrame.getEvaluator(); + final XDebuggerEvaluator evaluator = session.getDebugProcess().getEvaluator(); if (evaluator == null) { return null; } @@ -111,12 +102,9 @@ public class XQuickEvaluateHandler extends QuickEvaluateHandler { public int getValueLookupDelay(final Project project) { XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); if (session != null) { - XStackFrame stackFrame = session.getCurrentStackFrame(); - if (stackFrame != null) { - XDebuggerEvaluator evaluator = stackFrame.getEvaluator(); - if (evaluator != null) { - return evaluator.getValuePopupDelay(); - } + XDebuggerEvaluator evaluator = session.getDebugProcess().getEvaluator(); + if (evaluator != null) { + return evaluator.getValuePopupDelay(); } } return 700; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java index 415742b6a700..ebf5d69a166e 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java @@ -16,6 +16,10 @@ package com.intellij.xdebugger.impl.evaluate.quick; import com.intellij.codeInsight.hint.HintUtil; +import com.intellij.execution.console.LanguageConsoleImpl; +import com.intellij.execution.console.LanguageConsoleView; +import com.intellij.execution.impl.ConsoleViewImpl; +import com.intellij.execution.ui.ConsoleView; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -72,7 +76,17 @@ public class XValueHint extends AbstractValueHint { myEvaluator = evaluator; myDebugSession = session; myExpression = XDebuggerEvaluateActionHandler.getExpressionText(expressionData, editor.getDocument()); - final VirtualFile file = FileDocumentManager.getInstance().getFile(editor.getDocument()); + + VirtualFile file; + ConsoleView consoleView = ConsoleViewImpl.CONSOLE_VIEW_IN_EDITOR_VIEW.get(editor); + if (consoleView instanceof LanguageConsoleView) { + LanguageConsoleImpl console = ((LanguageConsoleView)consoleView).getConsole(); + file = console.getHistoryViewer() == editor ? console.getVirtualFile() : null; + } + else { + file = FileDocumentManager.getInstance().getFile(editor.getDocument()); + } + myExpressionPosition = file != null ? XDebuggerUtil.getInstance().createPositionByOffset(file, expressionData.first.getStartOffset()) : null; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/ValueLookupManager.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/ValueLookupManager.java index cd1cfe2b51a1..13facc097e93 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/ValueLookupManager.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/ValueLookupManager.java @@ -29,6 +29,7 @@ import com.intellij.openapi.editor.event.EditorMouseMotionListener; import com.intellij.openapi.project.Project; import com.intellij.util.Alarm; import com.intellij.xdebugger.impl.DebuggerSupport; +import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -107,7 +108,7 @@ public class ValueLookupManager implements EditorMouseMotionListener { } } - public void showHint(final QuickEvaluateHandler handler, Editor editor, Point point, ValueHintType type) { + public void showHint(@NotNull QuickEvaluateHandler handler, @NotNull Editor editor, @NotNull Point point, @NotNull ValueHintType type) { myAlarm.cancelAllRequests(); if (editor.isDisposed() || !handler.canShowHint(myProject)) { return; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java index 48defd3a08e9..088b4004798b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java @@ -123,8 +123,7 @@ public class XWatchesViewImpl implements DnDNativeTarget, XWatchesView, XDebugVi @Override public void addWatchExpression(@NotNull String expression, int index, final boolean navigateToWatchNode) { - XStackFrame stackFrame = mySession.getCurrentStackFrame(); - myRootNode.addWatchExpression(stackFrame == null ? null : stackFrame.getEvaluator(), expression, index, navigateToWatchNode); + myRootNode.addWatchExpression(mySession.getDebugProcess().getEvaluator(), expression, index, navigateToWatchNode); updateSessionData(); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java index abce43b858ec..d09bc7f37b65 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java @@ -141,6 +141,7 @@ public class DebuggerUIUtil { final Ref<Balloon> balloonRef = Ref.create(null); final Ref<Boolean> isLoading = Ref.create(Boolean.FALSE); + final Ref<Boolean> moreOptionsRequested = Ref.create(Boolean.FALSE); propertiesPanel.setDelegate(new XLightBreakpointPropertiesPanel.Delegate() { @Override @@ -152,6 +153,7 @@ public class DebuggerUIUtil { balloonRef.get().hide(); } showXBreakpointEditorBalloon(project, point, component, true, breakpoint); + moreOptionsRequested.set(true); } }); @@ -159,10 +161,15 @@ public class DebuggerUIUtil { propertiesPanel.loadProperties(); isLoading.set(Boolean.FALSE); + if (moreOptionsRequested.get()) { + return; + } + Runnable showMoreOptions = new Runnable() { @Override public void run() { propertiesPanel.saveProperties(); + propertiesPanel.dispose(); BreakpointsDialogFactory.getInstance(project).showDialog(breakpoint); } }; @@ -184,6 +191,7 @@ public class DebuggerUIUtil { @Override public void onClosed(LightweightWindowEvent event) { propertiesPanel.saveProperties(); + propertiesPanel.dispose(); breakpointManager.removeBreakpointListener(breakpointListener); } }); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/ExecutionPointHighlighter.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/ExecutionPointHighlighter.java index 47485e568a14..db7aef7d61cb 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/ExecutionPointHighlighter.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/ExecutionPointHighlighter.java @@ -72,7 +72,7 @@ public class ExecutionPointHighlighter { public void navigateTo() { if (myOpenFileDescriptor != null) { - FileEditorManager.getInstance(myProject).openTextEditor(myOpenFileDescriptor, false); + FileEditorManager.getInstance(myProject).openTextEditor(myOpenFileDescriptor, true); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index e442654c560a..1aa9e2cb53fb 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -144,6 +144,9 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { if (XWatchesView.DATA_KEY.is(dataId)) { return myWatchesView; } + if (LangDataKeys.CONSOLE_VIEW.is(dataId)) { + return session.getConsoleView(); + } return null; } }); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/EvaluateInConsoleFromTreeAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/EvaluateInConsoleFromTreeAction.java new file mode 100644 index 000000000000..5bff527452c4 --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/EvaluateInConsoleFromTreeAction.java @@ -0,0 +1,32 @@ +package com.intellij.xdebugger.impl.ui.tree.actions; + +import com.intellij.execution.console.ConsoleExecuteAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.xdebugger.impl.actions.handlers.XEvaluateInConsoleFromEditorActionHandler; +import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class EvaluateInConsoleFromTreeAction extends XAddToWatchesAction { + @Override + protected boolean isEnabled(@NotNull XValueNodeImpl node, @NotNull AnActionEvent e) { + return super.isEnabled(node, e) && getConsoleExecuteAction(e) != null; + } + + @Nullable + private static ConsoleExecuteAction getConsoleExecuteAction(@NotNull AnActionEvent e) { + return XEvaluateInConsoleFromEditorActionHandler.getConsoleExecuteAction(e.getData(LangDataKeys.CONSOLE_VIEW)); + } + + @Override + protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) { + ConsoleExecuteAction action = getConsoleExecuteAction(e); + if (action != null) { + String expression = node.getValueContainer().getEvaluationExpression(); + if (expression != null) { + action.execute(null, expression, null); + } + } + } +}
\ No newline at end of file diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java index a3621cb1a621..eb6c1586f103 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java @@ -21,9 +21,9 @@ import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NotNull; /** - * @author nik + * This action works only in the variables view, it is not generic action like {@see com.intellij.xdebugger.impl.actions.AddToWatchesAction} */ -public class XAddToWatchesAction extends XDebuggerTreeActionBase { +class XAddToWatchesAction extends XDebuggerTreeActionBase { @Override protected boolean isEnabled(@NotNull final XValueNodeImpl node, @NotNull AnActionEvent e) { return super.isEnabled(node, e) && node.getValueContainer().getEvaluationExpression() != null && e.getData(XWatchesView.DATA_KEY) != null; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java index 379b07c5426a..1833ae34d1e5 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java @@ -44,7 +44,7 @@ public class EvaluatingExpressionRootNode extends XValueContainerNode<Evaluating public static class EvaluatingResultContainer extends XValueContainer implements XDebuggerTreeListener { private final XDebuggerEvaluationDialog myDialog; - private XDebuggerTree myTree; + private final XDebuggerTree myTree; public EvaluatingResultContainer(final XDebuggerEvaluationDialog dialog, XDebuggerTree tree) { myDialog = dialog; diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XBreakpointManagerTest.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XBreakpointManagerTest.java index 38e9154d936e..a4cd467e1627 100644 --- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XBreakpointManagerTest.java +++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XBreakpointManagerTest.java @@ -32,23 +32,26 @@ import java.util.List; public class XBreakpointManagerTest extends XBreakpointsTestCase { public void testAddRemove() { + XBreakpoint<MyBreakpointProperties> defaultBreakpoint = myBreakpointManager.getDefaultBreakpoint(MY_SIMPLE_BREAKPOINT_TYPE); + assertSameElements(getAllBreakpoints(), defaultBreakpoint); + XLineBreakpoint<MyBreakpointProperties> lineBreakpoint = myBreakpointManager.addLineBreakpoint(MY_LINE_BREAKPOINT_TYPE, "url", 239, new MyBreakpointProperties("123")); XBreakpoint<MyBreakpointProperties> breakpoint = myBreakpointManager.addBreakpoint(MY_SIMPLE_BREAKPOINT_TYPE, new MyBreakpointProperties("abc")); - assertSameElements(getAllBreakpoints(), breakpoint, lineBreakpoint); + assertSameElements(getAllBreakpoints(), breakpoint, lineBreakpoint, defaultBreakpoint); assertSame(lineBreakpoint, assertOneElement(myBreakpointManager.getBreakpoints(MY_LINE_BREAKPOINT_TYPE))); - assertSame(breakpoint, getSingleBreakpoint()); + assertSameElements(myBreakpointManager.getBreakpoints(MY_SIMPLE_BREAKPOINT_TYPE), breakpoint, defaultBreakpoint); myBreakpointManager.removeBreakpoint(lineBreakpoint); - assertSame(breakpoint, assertOneElement(getAllBreakpoints())); + assertSameElements(getAllBreakpoints(), breakpoint, defaultBreakpoint); assertTrue(myBreakpointManager.getBreakpoints(MY_LINE_BREAKPOINT_TYPE).isEmpty()); - assertSame(breakpoint, getSingleBreakpoint()); + assertSameElements(myBreakpointManager.getBreakpoints(MY_SIMPLE_BREAKPOINT_TYPE), breakpoint, defaultBreakpoint); myBreakpointManager.removeBreakpoint(breakpoint); - assertEmpty(getAllBreakpoints()); - assertTrue(myBreakpointManager.getBreakpoints(MY_SIMPLE_BREAKPOINT_TYPE).isEmpty()); + assertSameElements(getAllBreakpoints(), defaultBreakpoint); + assertSameElements(myBreakpointManager.getBreakpoints(MY_SIMPLE_BREAKPOINT_TYPE), defaultBreakpoint); } public void testSerialize() { diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java index 3e4067f19ca9..0f140e38f893 100644 --- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java +++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java @@ -65,7 +65,8 @@ public class XDebuggerTestUtil { XBreakpointManager manager = XDebuggerManager.getInstance(project).getBreakpointManager(); XLineBreakpointImpl breakpoint = (XLineBreakpointImpl)manager.findBreakpointAtLine(type, file, line); Assert.assertNotNull(breakpoint); - Assert.assertEquals(validity ? AllIcons.Debugger.Db_verified_breakpoint : AllIcons.Debugger.Db_invalid_breakpoint, breakpoint.getIcon()); + Assert + .assertEquals(validity ? AllIcons.Debugger.Db_verified_breakpoint : AllIcons.Debugger.Db_invalid_breakpoint, breakpoint.getIcon()); Assert.assertEquals(errorMessage, breakpoint.getErrorMessage()); } @@ -303,7 +304,8 @@ public class XDebuggerTestUtil { expectedNames.removeAll(actualNames); UsefulTestCase.assertTrue("Missing variables:" + StringUtil.join(expectedNames, ", ") + "\nAll Variables: " + StringUtil.join(actualNames, ", "), - expectedNames.isEmpty()); + expectedNames.isEmpty() + ); } public static void assertSourcePosition(final XValue value, VirtualFile file, int offset) { @@ -366,8 +368,23 @@ public class XDebuggerTestUtil { public static void removeAllBreakpoints(@NotNull final Project project) { final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); XBreakpoint<?>[] breakpoints = breakpointManager.getAllBreakpoints(); - for (XBreakpoint b : breakpoints) { - breakpointManager.removeBreakpoint(b); + for (final XBreakpoint b : breakpoints) { + new WriteAction() { + @Override + protected void run(Result result) throws Throwable { + breakpointManager.removeBreakpoint(b); + } + }.execute(); + } + } + + public static <B extends XBreakpoint<?>> + void setDefaultBreakpointEnabled(@NotNull final Project project, Class<? extends XBreakpointType<B, ?>> bpTypeClass, boolean enabled) { + final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); + XBreakpointType<B, ?> bpType = XDebuggerUtil.getInstance().findBreakpointType(bpTypeClass); + XBreakpoint<?> bp = breakpointManager.getDefaultBreakpoint(bpType); + if (bp != null) { + bp.setEnabled(enabled); } } diff --git a/plugins/IdeaTestAssistant/src/com/intellij/testAssistant/TestDataGroupVirtualFile.java b/plugins/IdeaTestAssistant/src/com/intellij/testAssistant/TestDataGroupVirtualFile.java index c44b49cd71b9..069ef03c8277 100644 --- a/plugins/IdeaTestAssistant/src/com/intellij/testAssistant/TestDataGroupVirtualFile.java +++ b/plugins/IdeaTestAssistant/src/com/intellij/testAssistant/TestDataGroupVirtualFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -43,7 +43,7 @@ public class TestDataGroupVirtualFile extends VirtualFile { @Override public String getName() { final String prefix = StringUtil.commonPrefix(myBeforeFile.getName(), myAfterFile.getName()); - if (prefix.length() == 0) { + if (prefix.isEmpty()) { return StringUtil.commonSuffix(myBeforeFile.getName(), myAfterFile.getName()); } return prefix + "." + myBeforeFile.getExtension(); @@ -63,6 +63,7 @@ public class TestDataGroupVirtualFile extends VirtualFile { return LocalFileSystem.getInstance(); } + @NotNull @Override public String getPath() { return myBeforeFile.getPath(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index dddb6e1d3988..4becc9723a65 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -2489,6 +2489,9 @@ <localInspection language="JAVA" suppressId="LockAcquiredButNotSafelyReleased" shortName="SafeLock" bundle="com.siyeh.InspectionGadgetsBundle" key="safe.lock.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.threading.issues" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.threading.SafeLockInspection"/> + <localInspection language="JAVA" suppressId="SharedThreadLocalRandom" shortName="SharedThreadLocalRandom" bundle="com.siyeh.InspectionGadgetsBundle" + key="shared.thread.local.random.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.threading.issues" + enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.threading.SharedThreadLocalRandomInspection"/> <localInspection language="JAVA" shortName="SignalWithoutCorrespondingAwait" bundle="com.siyeh.InspectionGadgetsBundle" key="signal.without.corresponding.await.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.threading.issues" enabledByDefault="false" level="WARNING" @@ -2640,6 +2643,10 @@ bundle="com.siyeh.InspectionGadgetsBundle" key="parameter.hides.member.variable.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.visibility.issues" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.visibility.ParameterHidingMemberVariableInspection"/> + <localInspection language="JAVA" suppressId="LambdaParameterHidesMemberVariable" shortName="LambdaParameterHidingMemberVariable" + bundle="com.siyeh.InspectionGadgetsBundle" key="lambda.parameter.hides.member.variable.display.name" + groupBundle="messages.InspectionsBundle" groupKey="group.names.visibility.issues" enabledByDefault="false" + level="WARNING" implementationClass="com.siyeh.ig.visibility.LambdaParameterHidingMemberVariableInspection"/> </extensions> <application-components> diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 7f61b374c9a9..013cf2344b2a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1157,7 +1157,7 @@ local.variable.naming.convention.problem.descriptor.long=Local variable name <co local.variable.naming.convention.problem.descriptor.regex.mismatch=Local variable name <code>#ref</code> doesn''t match regex ''{0}'' #loc local.variable.naming.convention.ignore.option=Ignore for-loop parameters local.variable.naming.convention.ignore.catch.option=Ignore 'catch' block parameters -method.names.differ.only.by.case.problem.descriptor=Method names <code>#ref</code> and ''{0}'' differ only by case #loc +method.names.differ.only.by.case.problem.descriptor=Method name <code>#ref</code> and method name ''{0}'' differ only by case #loc parameter.name.differs.from.overridden.parameter.ignore.character.option=Ignore if overridden parameter contains only one character parameter.name.differs.from.overridden.parameter.ignore.library.option=Ignore if overridden parameter is from a library parameter.name.differs.from.overridden.parameter.problem.descriptor=Parameter name <code>#ref</code> is different from parameter ''{0}'' overridden #loc @@ -2066,3 +2066,8 @@ implicit.default.charset.usage.constructor.problem.descriptor=<code>new #ref()</ interface.may.be.annotated.functional.display.name=Interface may be annotated @FunctionalInterface interface.may.be.annotated.functional.problem.descriptor=Interface <code>#ref</code> may be annotated with @FunctionalInterface only.report.public.methods.option=Only report 'public' methods +lambda.parameter.hides.member.variable.display.name=Lambda parameter hides field +lambda.parameter.hides.member.variable.problem.descriptor=Lambda parameter <code>#ref</code> hides field in class ''{0}'' #loc +shared.thread.local.random.display.name='ThreadLocalRandom' instance might be shared +shared.thread.local.random.problem.descriptor='ThreadLocalRandom' instance might be shared between threads + diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFix.java index 9ef4c14e4a84..31a7987f40f1 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFix.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 Bas Leijdekkers + * Copyright 2008-2014 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.InspectionGadgetsFix; @@ -46,8 +45,7 @@ public class ExtractParameterAsLocalVariableFix } @Override - public void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { + public void doFix(Project project, ProblemDescriptor descriptor) { final PsiReferenceExpression parameterReference = (PsiReferenceExpression)descriptor.getPsiElement(); final PsiElement target = parameterReference.resolve(); @@ -79,6 +77,10 @@ public class ExtractParameterAsLocalVariableFix body = forBody; } } + else if (declarationScope instanceof PsiLambdaExpression) { + final PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)declarationScope; + body = lambdaExpression.getBody(); + } else { return; } @@ -125,15 +127,16 @@ public class ExtractParameterAsLocalVariableFix replaceVariableName(child, firstReference, variableName, parameterName, buffer); } + if (body instanceof PsiExpression) { // expression lambda + buffer.insert(0, "return "); + buffer.append(';'); + } final String replacementText; if (newDeclarationCreated) { replacementText = "{" + buffer + '}'; } else { - final PsiType type = parameterReference.getType(); - if (type == null) { - return; - } + final PsiType type = parameter.getType(); final String className = type.getCanonicalText(); replacementText = '{' + className + ' ' + variableName + " = " + parameterName + ';' + buffer + '}'; @@ -141,8 +144,7 @@ public class ExtractParameterAsLocalVariableFix final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); final PsiCodeBlock block = - elementFactory.createCodeBlockFromText( - replacementText, null); + elementFactory.createCodeBlockFromText(replacementText, declarationScope); body.replace(block); codeStyleManager.reformat(declarationScope); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java index 278c07e980c0..3741d260dae6 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ public class ControlFlowUtils { } else if (statement instanceof PsiExpressionListStatement || statement instanceof PsiEmptyStatement || statement instanceof PsiAssertStatement || statement instanceof PsiDeclarationStatement || - statement instanceof PsiSwitchLabelStatement) { + statement instanceof PsiSwitchLabelStatement || statement instanceof PsiForeachStatement) { return true; } else if (statement instanceof PsiExpressionStatement) { @@ -63,9 +63,6 @@ public class ControlFlowUtils { else if (statement instanceof PsiForStatement) { return forStatementMayCompleteNormally((PsiForStatement)statement); } - else if (statement instanceof PsiForeachStatement) { - return foreachStatementMayCompleteNormally((PsiForeachStatement)statement); - } else if (statement instanceof PsiWhileStatement) { return whileStatementMayCompleteNormally((PsiWhileStatement)statement); } @@ -130,10 +127,6 @@ public class ControlFlowUtils { return Boolean.TRUE != value; } - private static boolean foreachStatementMayCompleteNormally(@NotNull PsiForeachStatement loopStatement) { - return true; - } - private static boolean switchStatementMayCompleteNormally(@NotNull PsiSwitchStatement switchStatement) { if (statementIsBreakTarget(switchStatement)) { return true; @@ -524,7 +517,7 @@ public class ControlFlowUtils { } } - private static class SystemExitFinder extends JavaRecursiveElementVisitor { + private static class SystemExitFinder extends JavaRecursiveElementWalkingVisitor { private boolean m_found = false; @@ -564,7 +557,7 @@ public class ControlFlowUtils { } } - private static class ReturnFinder extends JavaRecursiveElementVisitor { + private static class ReturnFinder extends JavaRecursiveElementWalkingVisitor { private boolean m_found = false; @@ -587,7 +580,7 @@ public class ControlFlowUtils { } } - private static class BreakFinder extends JavaRecursiveElementVisitor { + private static class BreakFinder extends JavaRecursiveElementWalkingVisitor { private boolean m_found = false; private final PsiStatement m_target; @@ -637,7 +630,7 @@ public class ControlFlowUtils { } } - private static class ContinueFinder extends JavaRecursiveElementVisitor { + private static class ContinueFinder extends JavaRecursiveElementWalkingVisitor { private boolean m_found = false; private final PsiStatement m_target; @@ -687,7 +680,7 @@ public class ControlFlowUtils { } } - private static class MethodCallFinder extends JavaRecursiveElementVisitor { + private static class MethodCallFinder extends JavaRecursiveElementWalkingVisitor { private final String containingClassName; private final PsiType returnType; @@ -728,7 +721,7 @@ public class ControlFlowUtils { } } - private static class ContinueToAncestorFinder extends JavaRecursiveElementVisitor { + private static class ContinueToAncestorFinder extends JavaRecursiveElementWalkingVisitor { private final PsiStatement statement; private boolean found = false; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java index c14da9f55373..ad5ecc2351f3 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java @@ -153,86 +153,59 @@ public class ExpectedTypeUtils { } @Override - public void visitBinaryExpression(@NotNull PsiBinaryExpression binaryExpression) { - final PsiExpression rhs = binaryExpression.getROperand(); - if (rhs == null) { - expectedType = null; - return; - } - final PsiExpression lhs = binaryExpression.getLOperand(); - PsiType lhsType = lhs.getType(); - if (lhsType == null) { - expectedType = null; - return; - } - PsiType rhsType = rhs.getType(); - if (rhsType == null) { - expectedType = null; - return; + public void visitPolyadicExpression(@NotNull PsiPolyadicExpression polyadicExpression) { + final PsiExpression[] operands = polyadicExpression.getOperands(); + for (PsiExpression operand : operands) { + if (operand == null || operand.getType() == null) { + expectedType = null; + return; + } } - final IElementType tokenType = binaryExpression.getOperationTokenType(); - final PsiType type = binaryExpression.getType(); + final IElementType tokenType = polyadicExpression.getOperationTokenType(); + final PsiType type = polyadicExpression.getType(); + final PsiType wrappedExpressionType = wrappedExpression.getType(); if (TypeUtils.isJavaLangString(type) || isArithmeticOperation(tokenType) || isBooleanOperation(tokenType)) { expectedType = type; } else if (isShiftOperation(tokenType)) { - if (lhs == wrappedExpression) { - expectedType = unaryNumericPromotion(lhsType); - } - else { - expectedType = unaryNumericPromotion(rhsType); - } + expectedType = unaryNumericPromotion(wrappedExpressionType); } - else if (ComparisonUtils.isEqualityComparison(binaryExpression)) { + else if (ComparisonUtils.isEqualityComparison(polyadicExpression)) { // JLS 15.21.1 Numerical Equality Operators == and != - final PsiType wrappedExpressionType = wrappedExpression.getType(); if (TypeConversionUtil.isPrimitiveAndNotNull(wrappedExpressionType)) { expectedType = wrappedExpressionType; - return; } - if (lhs == wrappedExpression) { - if (TypeConversionUtil.isPrimitiveAndNotNull(rhsType)) { + else if (operands.length > 2) { + expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); + } + else if (operands[0] == wrappedExpression) { + if (TypeConversionUtil.isPrimitiveAndNotNull(operands[1].getType())) { expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); - return; } - expectedType = TypeUtils.getObjectType(wrappedExpression); + else { + expectedType = TypeUtils.getObjectType(wrappedExpression); + } } else { - if (TypeConversionUtil.isPrimitiveAndNotNull(lhsType)) { + if (TypeConversionUtil.isPrimitiveAndNotNull(operands[0].getType())) { expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); - return; - } - expectedType = TypeUtils.getObjectType(wrappedExpression); + } + else { + expectedType = TypeUtils.getObjectType(wrappedExpression); + } } } else if (ComparisonUtils.isComparisonOperation(tokenType)) { - if (lhs == wrappedExpression && !TypeConversionUtil.isPrimitiveAndNotNull(lhsType)) { - lhsType = PsiPrimitiveType.getUnboxedType(lhsType); - if (lhsType == null) { - expectedType = null; - return; - } + if (operands.length != 2) { + expectedType = null; + return; } - if (rhs == wrappedExpression && !TypeConversionUtil.isPrimitiveAndNotNull(rhsType)) { - rhsType = PsiPrimitiveType.getUnboxedType(rhsType); - if (rhsType == null) { - expectedType = null; + else if (!TypeConversionUtil.isPrimitiveAndNotNull(wrappedExpressionType)) { + if (PsiPrimitiveType.getUnboxedType(wrappedExpressionType) == null) { return; } } - // JLS 5.6.2 Binary Numeric Promotion - if (PsiType.DOUBLE.equals(lhsType) || PsiType.DOUBLE.equals(rhsType)) { - expectedType = PsiType.DOUBLE; - } - else if (PsiType.FLOAT.equals(lhsType) || PsiType.FLOAT.equals(rhsType)) { - expectedType = PsiType.FLOAT; - } - else if (PsiType.LONG.equals(lhsType) || PsiType.LONG.equals(rhsType)) { - expectedType = PsiType.LONG; - } - else { - expectedType = PsiType.INT; - } + expectedType = TypeConversionUtil.binaryNumericPromotion(operands[0].getType(), operands[1].getType()); } else { expectedType = null; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java index 6301e83eb0fd..8d52a8619dc5 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,8 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleSettingsFacade; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.*; +import com.intellij.psi.util.InheritanceUtil; import com.siyeh.HardcodedMethodConstants; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -247,20 +247,22 @@ public class ImportUtils { continue; } final PsiElement element = importReference.resolve(); - if (element == null || !(element instanceof PsiPackage)) { + if (!(element instanceof PsiPackage)) { continue; } final PsiPackage aPackage = (PsiPackage)element; - if (!strict) { - return aPackage.containsClassNamed(shortName); + if (!strict && aPackage.containsClassNamed(shortName)) { + return true; } - final PsiClass[] classes = aPackage.findClassByShortName(shortName, file.getResolveScope()); - for (final PsiClass aClass : classes) { - final String qualifiedClassName = aClass.getQualifiedName(); - if (qualifiedClassName == null || fqName.equals(qualifiedClassName)) { - continue; + else { + final PsiClass[] classes = aPackage.findClassByShortName(shortName, file.getResolveScope()); + for (final PsiClass aClass : classes) { + final String qualifiedClassName = aClass.getQualifiedName(); + if (qualifiedClassName == null || fqName.equals(qualifiedClassName)) { + continue; + } + return containsConflictingReference(file, qualifiedClassName); } - return containsConflictingReference(file, qualifiedClassName); } } return hasJavaLangImportConflict(fqName, file); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java index af04c02d6e79..5063ef7c2ea7 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ public class SideEffectChecker { return visitor.mayHaveSideEffects(); } - private static class SideEffectsVisitor extends JavaRecursiveElementVisitor { + private static class SideEffectsVisitor extends JavaRecursiveElementWalkingVisitor { private boolean mayHaveSideEffects = false; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java index e097d58f8301..b8e7b7c183d8 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,9 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.Set; public class VariableAccessUtils { @@ -446,4 +449,43 @@ public class VariableAccessUtils { } return child; } + + public static Set<PsiVariable> collectUsedVariables(PsiElement context) { + if (context == null) { + return Collections.emptySet(); + } + final VariableCollectingVisitor visitor = new VariableCollectingVisitor(); + context.accept(visitor); + return visitor.getUsedVariables(); + } + + public static boolean isAnyVariableAssigned(@NotNull Collection<PsiVariable> variables, @Nullable PsiElement context) { + if (context == null) { + return false; + } + final VariableAssignedVisitor visitor = new VariableAssignedVisitor(variables, true); + context.accept(visitor); + return visitor.isAssigned(); + } + + private static class VariableCollectingVisitor extends JavaRecursiveElementVisitor { + + private final Set<PsiVariable> usedVariables = new HashSet(); + + @Override + public void visitReferenceExpression( + PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement target = expression.resolve(); + if (!(target instanceof PsiVariable)) { + return; + } + final PsiVariable variable = (PsiVariable)target; + usedVariables.add(variable); + } + + public Set<PsiVariable> getUsedVariables() { + return usedVariables; + } + } }
\ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java index 0a22ef3fde97..279400f3a653 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,16 +20,25 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.Collections; + public class VariableAssignedVisitor extends JavaRecursiveElementWalkingVisitor { - @NotNull private final PsiVariable variable; + @NotNull private final Collection<PsiVariable> variables; private final boolean recurseIntoClasses; private final boolean checkUnaryExpressions; private boolean assigned = false; private PsiElement excludedElement = null; + public VariableAssignedVisitor(@NotNull Collection<PsiVariable> variables, boolean recurseIntoClasses) { + this.variables = variables; + checkUnaryExpressions = true; + this.recurseIntoClasses = recurseIntoClasses; + } + public VariableAssignedVisitor(@NotNull PsiVariable variable, boolean recurseIntoClasses) { - this.variable = variable; + variables = Collections.singleton(variable); final PsiType type = variable.getType(); checkUnaryExpressions = TypeConversionUtil.isNumericType(type); this.recurseIntoClasses = recurseIntoClasses; @@ -58,8 +67,11 @@ public class VariableAssignedVisitor extends JavaRecursiveElementWalkingVisitor } super.visitAssignmentExpression(assignment); final PsiExpression lhs = assignment.getLExpression(); - if (VariableAccessUtils.evaluatesToVariable(lhs, variable)) { - assigned = true; + for (PsiVariable variable : variables) { + if (VariableAccessUtils.evaluatesToVariable(lhs, variable)) { + assigned = true; + break; + } } } @@ -85,8 +97,11 @@ public class VariableAssignedVisitor extends JavaRecursiveElementWalkingVisitor return; } final PsiExpression operand = prefixExpression.getOperand(); - if (VariableAccessUtils.evaluatesToVariable(operand, variable)) { - assigned = true; + for (PsiVariable variable : variables) { + if (VariableAccessUtils.evaluatesToVariable(operand, variable)) { + assigned = true; + break; + } } } @@ -104,8 +119,11 @@ public class VariableAssignedVisitor extends JavaRecursiveElementWalkingVisitor return; } final PsiExpression operand = postfixExpression.getOperand(); - if (VariableAccessUtils.evaluatesToVariable(operand, variable)) { - assigned = true; + for (PsiVariable variable : variables) { + if (VariableAccessUtils.evaluatesToVariable(operand, variable)) { + assigned = true; + break; + } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java new file mode 100644 index 000000000000..97adc033c5b1 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java @@ -0,0 +1,122 @@ +/* + * 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. + * 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.siyeh.ig.threading; + +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class SharedThreadLocalRandomInspection extends BaseInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("shared.thread.local.random.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("shared.thread.local.random.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new SharedThreadLocalRandomVisitor(); + } + + private static class SharedThreadLocalRandomVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + @NonNls final String name = methodExpression.getReferenceName(); + if (!"current".equals(name)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (!InheritanceUtil.isInheritor(aClass, "java.util.concurrent.ThreadLocalRandom")) { + return; + } + if (isArgumentToMethodCall(expression)) { + registerMethodCallError(expression); + } + else { + final PsiVariable variable = assignedToVariable(expression); + if (variable instanceof PsiField) { + registerMethodCallError(expression); + } + else if (variable instanceof PsiLocalVariable) { + final PsiCodeBlock context = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, context) || + VariableAccessUtils.variableIsUsedInInnerClass(variable, context)) { + registerMethodCallError(expression); + } + } + } + } + + private static boolean isArgumentToMethodCall(PsiExpression expression) { + final PsiElement parent = ParenthesesUtils.getParentSkipParentheses(expression); + if (!(parent instanceof PsiExpressionList)) { + return false; + } + final PsiElement grandParent = parent.getParent(); + return grandParent instanceof PsiMethodCallExpression; + } + + private static PsiVariable assignedToVariable(PsiMethodCallExpression expression) { + final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class); + if (parent instanceof PsiVariable) { + return (PsiVariable)parent; + } + if (!(parent instanceof PsiAssignmentExpression)) { + return null; + } + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent; + final PsiExpression rhs = assignmentExpression.getRExpression(); + if (!PsiTreeUtil.isAncestor(rhs, expression, false)) { + return null; + } + final PsiExpression lhs = ParenthesesUtils.stripParentheses(assignmentExpression.getLExpression()); + if (!(lhs instanceof PsiReferenceExpression)) { + return null; + } + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs; + final PsiElement target = referenceExpression.resolve(); + if (!(target instanceof PsiVariable)) { + return null; + } + return (PsiVariable)target; + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionBase.java new file mode 100644 index 000000000000..5b245eccc0a0 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionBase.java @@ -0,0 +1,110 @@ +/* + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers + * + * 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.siyeh.ig.visibility; + +import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; +import com.intellij.psi.*; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.ClassUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class LambdaParameterHidingMemberVariableInspectionBase extends BaseInspection { + + @SuppressWarnings("PublicField") + public boolean m_ignoreInvisibleFields = true; + + @Override + @NotNull + public String getID() { + return "LambdaParameterHidesMemberVariable"; + } + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message("lambda.parameter.hides.member.variable.display.name"); + } + + @Override + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + final PsiClass aClass = (PsiClass)infos[0]; + return InspectionGadgetsBundle.message("lambda.parameter.hides.member.variable.problem.descriptor", aClass.getName()); + } + + @Override + public JComponent createOptionsPanel() { + final MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this); + optionsPanel.addCheckbox(InspectionGadgetsBundle.message("parameter.hides.member.variable.ignore.superclass.option"), + "m_ignoreInvisibleFields"); + return optionsPanel; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new LambdaParameterHidingMemberVariableVisitor(); + } + + private class LambdaParameterHidingMemberVariableVisitor extends BaseInspectionVisitor { + + @Override + public void visitParameter(@NotNull PsiParameter variable) { + super.visitParameter(variable); + final PsiElement declarationScope = variable.getDeclarationScope(); + if (!(declarationScope instanceof PsiLambdaExpression)) { + return; + } + final PsiClass aClass = checkFieldName(variable); + if (aClass == null) { + return; + } + registerVariableError(variable, aClass); + } + + @Nullable + private PsiClass checkFieldName(PsiVariable variable) { + final String variableName = variable.getName(); + if (variableName == null) { + return null; + } + PsiClass aClass = ClassUtils.getContainingClass(variable); + while (aClass != null) { + final PsiField[] fields = aClass.getAllFields(); + for (PsiField field : fields) { + final String fieldName = field.getName(); + if (!variableName.equals(fieldName)) { + continue; + } + if (!m_ignoreInvisibleFields || ClassUtils.isFieldVisible(field, aClass)) { + return aClass; + } + } + aClass = ClassUtils.getContainingClass(aClass); + } + return null; + } + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspection.java new file mode 100644 index 000000000000..4112dfe911da --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspection.java @@ -0,0 +1,26 @@ +/* + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers + * + * 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.siyeh.ig.visibility; + +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.fixes.RenameFix; + +public class LambdaParameterHidingMemberVariableInspection extends LambdaParameterHidingMemberVariableInspectionBase { + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new RenameFix(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LambdaParameterHidingMemberVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LambdaParameterHidingMemberVariable.html new file mode 100644 index 000000000000..3817e402e632 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LambdaParameterHidingMemberVariable.html @@ -0,0 +1,11 @@ +<html> +<body> +Reports lambda parameters named identically to visible fields of the surrounding classes +and their superclasses. +<!-- tooltip end --> +<p> +Use the checkbox below to ignore fields that are not actually visible from the lambda expression, for example <b>private</b> fields +<p> +<small>New in 13.1</small> +</body> +</html>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SharedThreadLocalRandom.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SharedThreadLocalRandom.html new file mode 100644 index 000000000000..07ebccab4653 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SharedThreadLocalRandom.html @@ -0,0 +1,15 @@ +<html> +<body> +Reports <b>java.util.concurrent.ThreadLocalRandom</b> instances which might be shared between threads. +A <b>ThreadLocalRandom</b> might be shared between threads and is reported when it is assigned to a field, +used as a method argument or assigned to a local variable and used in anonymous or nested classes. +A <b>ThreadLocalRandom</b> should not be shared between threads because that is not thread-safe. +<p> +Usages of <b>ThreadLocalRandom</b> should typically look like <b>ThreadLocalRandom.current().nextInt(...)</b> +(or <b>nextDouble(...)</b> etc.). +When all usages are in this form, <b>ThreadLocalRandom</b> instances can not be used accidentally by multiple threads. +<!-- tooltip end --> +<p> +<small>New in 13.1</small> +</body> +</html>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadLocalNotStaticFinal.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadLocalNotStaticFinal.html index 2cb9e55aa170..e78d9c1e5afe 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadLocalNotStaticFinal.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadLocalNotStaticFinal.html @@ -1,5 +1,6 @@ <html> <body> +Reports fields of type <b>java.lang.ThreadLocal</b> which are not declared <b>static final</b>. In the most common case a <b>java.lang.ThreadLocal</b> instance associates state with a thread. A non-static non-final <b>java.lang.ThreadLocal</b> field associates state with diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java index a39bd53e4407..e598f0758a64 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/AutoUnboxing.java @@ -59,4 +59,8 @@ public class AutoUnboxing { if ((boolean) b) {} if ((int)n) {} } + + boolean polyadic() { + return true && Boolean.TRUE && true; + } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml index 431f5ca55078..a1ceb62b0486 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk/auto_unboxing/expected.xml @@ -106,4 +106,10 @@ <description>Auto-unboxing <code>n</code> #loc</description> </problem> + <problem> + <file>AutoUnboxing.java</file> + <line>64</line> + <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Auto-unboxing</problem_class> + <description>Auto-unboxing <code>Boolean.TRUE</code> #loc</description> + </problem> </problems>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/method_names_differ_only_by_case/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/method_names_differ_only_by_case/expected.xml index 570e237c7063..3c9a518635fc 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/method_names_differ_only_by_case/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/method_names_differ_only_by_case/expected.xml @@ -4,35 +4,35 @@ <file>MethodNamesDifferOnlyByCase.java</file> <line>20</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Method names differing only by case</problem_class> - <description>Method names <code>hashcode</code> and 'hashCode' differ only by case #loc</description> + <description>Method name <code>hashcode</code> and method name 'hashCode' differ only by case #loc</description> </problem> <problem> <file>MethodNamesDifferOnlyByCase.java</file> <line>30</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Method names differing only by case</problem_class> - <description>Method names <code>xX</code> and 'xx' differ only by case #loc</description> + <description>Method name <code>xX</code> and method name 'xx' differ only by case #loc</description> </problem> <problem> <file>MethodNamesDifferOnlyByCase.java</file> <line>5</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Method names differing only by case</problem_class> - <description>Method names <code>fooBar</code> and 'fooBAr' differ only by case #loc</description> + <description>Method name <code>fooBar</code> and method name 'fooBAr' differ only by case #loc</description> </problem> <problem> <file>MethodNamesDifferOnlyByCase.java</file> <line>10</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Method names differing only by case</problem_class> - <description>Method names <code>fooBAr</code> and 'fooBar' differ only by case #loc</description> + <description>Method name <code>fooBAr</code> and method name 'fooBar' differ only by case #loc</description> </problem> <problem> <file>MethodNamesDifferOnlyByCase.java</file> <line>29</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Method names differing only by case</problem_class> - <description>Method names <code>xx</code> and 'xX' differ only by case #loc</description> + <description>Method name <code>xx</code> and method name 'xX' differ only by case #loc</description> </problem> </problems>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java index b56c340f5400..2ce63ec4814e 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java @@ -21,6 +21,7 @@ import com.intellij.openapi.application.PluginPathManager; import com.intellij.pom.java.LanguageLevel; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; +import com.intellij.util.ArrayUtil; import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -38,19 +39,33 @@ public abstract class IGQuickFixesTestCase extends JavaCodeInsightFixtureTestCas protected void setUp() throws Exception { super.setUp(); - final BaseInspection inspection = getInspection(); - if (inspection != null) { - myFixture.enableInspections(inspection); + for (String environmentClass : getEnvironmentClasses()) { + myFixture.addClass(environmentClass); } + myFixture.enableInspections(getInspections()); } protected BaseInspection getInspection() { return null; } + protected BaseInspection[] getInspections() { + final BaseInspection inspection = getInspection(); + if (inspection != null) { + return new BaseInspection[] {inspection}; + } + return new BaseInspection[0]; + } + + @NonNls + @Language("JAVA") + protected String[] getEnvironmentClasses() { + return ArrayUtil.EMPTY_STRING_ARRAY; + } + @Override protected void tuneFixture(final JavaModuleFixtureBuilder builder) throws Exception { - builder.setLanguageLevel(LanguageLevel.JDK_1_7); + builder.setLanguageLevel(LanguageLevel.JDK_1_8); } @Override @@ -79,16 +94,16 @@ public abstract class IGQuickFixesTestCase extends JavaCodeInsightFixtureTestCas protected void doExpressionTest( String hint, - @Language(value = "JAVA", prefix = "class X {{System.out.print(", suffix = ");}}") @NotNull @NonNls String before, - @Language(value = "JAVA", prefix = "class X {{System.out.print(", suffix = ");}}") @NotNull @NonNls String after) { - doTest(hint, "class X {{System.out.print(" + before + ");}}", "class X {{System.out.print(" + after + ");}}"); + @Language(value = "JAVA", prefix = "class $X$ {{System.out.print(", suffix = ");}}") @NotNull @NonNls String before, + @Language(value = "JAVA", prefix = "class $X$ {{System.out.print(", suffix = ");}}") @NotNull @NonNls String after) { + doTest(hint, "class $X$ {{System.out.print(" + before + ");}}", "class $X$ {{System.out.print(" + after + ");}}"); } protected void doMemberTest( String hint, - @Language(value = "JAVA", prefix = "class X {", suffix = "}") @NotNull @NonNls String before, - @Language(value = "JAVA", prefix = "class X {", suffix = "}") @NotNull @NonNls String after) { - doTest(hint, "class X {" + before + "}", "class X {" + after + "}"); + @Language(value = "JAVA", prefix = "class $X$ {", suffix = "}") @NotNull @NonNls String before, + @Language(value = "JAVA", prefix = "class $X$ {", suffix = "}") @NotNull @NonNls String after) { + doTest(hint, "class $X$ {" + before + "}", "class $X$ {\n " + after + "\n}"); } protected void doTest(String hint, @Language("JAVA") @NotNull @NonNls String before, @Language("JAVA") @NotNull @NonNls String after) { diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFixTest.java new file mode 100644 index 000000000000..b8b74aecf249 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFixTest.java @@ -0,0 +1,121 @@ +/* + * 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. + * 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.siyeh.ig.fixes; + +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.IGQuickFixesTestCase; +import com.siyeh.ig.assignment.AssignmentToCatchBlockParameterInspection; +import com.siyeh.ig.assignment.AssignmentToForLoopParameterInspection; +import com.siyeh.ig.assignment.AssignmentToMethodParameterInspection; + +/** + * @author Bas Leijdekkers + */ +public class ExtractParameterAsLocalVariableFixTest extends IGQuickFixesTestCase { + + + @Override + protected BaseInspection[] getInspections() { + final AssignmentToForLoopParameterInspection inspection2 = new AssignmentToForLoopParameterInspection(); + inspection2.m_checkForeachParameters = true; + return new BaseInspection[] { + new AssignmentToMethodParameterInspection(), + inspection2, + new AssignmentToCatchBlockParameterInspection() + }; + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] {"class A {}", + "public interface Function<T, R> {\n" + + " R apply(T t);" + + "}"}; + } + + public void testLambdaWithExpressionBody() { + doTest( + InspectionGadgetsBundle.message("extract.parameter.as.local.variable.quickfix"), + "class X {" + + " Function<A, A> f = (a) -> a/**/ = null;" + + "}", + "class X {" + + " Function<A, A> f = (a) -> {\n" + + " A a1 = a;\n" + + " return a1 = null;\n" + + "};}" + ); + } + + public void testSimpleMethod() { + doTest( + InspectionGadgetsBundle.message("extract.parameter.as.local.variable.quickfix"), + "class X {" + + " void m(String s) {" + + " /**/s = \"hello\";" + + " System.out.println(s);" + + " }" + + "}", + "class X {\n" + + " void m(String s) {\n" + + " String s1 = \"hello\";\n" + + " System.out.println(s1);\n" + + " }\n" + + "}" + ); + } + + public void testSimpleForeach() { + doTest( + InspectionGadgetsBundle.message("extract.parameter.as.local.variable.quickfix"), + "class X {" + + " void m() {" + + " for (String s : new String[]{\"one\", \"two\", \"three\"})" + + " s/**/ = \"four\";" + + "}}", + "class X {" + + " void m() {\n" + + " for (String s : new String[]{\"one\", \"two\", \"three\"}){\n" + + " String s1 = \"four\";\n" + + " }\n" + + "}}" + ); + } + + public void testSimleCatchBlock() { + doTest( + InspectionGadgetsBundle.message("extract.parameter.as.local.variable.quickfix"), + "class X {" + + " void m() {" + + " try (java.io.InputStream in = null) {" + + " } catch (java.io.IOException e) {" + + " e/**/ = null;" + + " System.out.println(e);" + + " }" + + " }" + + "}", + "class X {" + + " void m() {" + + " try (java.io.InputStream in = null) {" + + " } catch (java.io.IOException e) {\n" + + " java.io.IOException e1 = null;\n" + + " System.out.println(e1);\n" + + "}\n" + + "}}" + ); + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/imports/UnusedImportInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/imports/UnusedImportInspectionTest.java index 9f19674a7cee..d9dda5abc6a9 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/imports/UnusedImportInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/imports/UnusedImportInspectionTest.java @@ -87,6 +87,21 @@ public class UnusedImportInspectionTest extends LightInspectionTestCase { "}"); } + public void testNoWarn() { + addEnvironmentClass("package java.awt; public class List extends Component {}"); + doTest("import javax.swing.*;\n" + + "import java.awt.*;\n" + + "import java.util.*;\n" + + "import java.util.List;\n" + + "\n" + + "class ImportTest extends Component {\n" + + "\n" + + " Collection<String> c;\n" + + " List<Integer> l;\n" + + " JComponent jc;\n" + + "}"); + } + @Override protected LocalInspectionTool getInspection() { return new UnusedImportInspection(); diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/SharedThreadLocalRandomInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/SharedThreadLocalRandomInspectionTest.java new file mode 100644 index 000000000000..b15bc350fd6b --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/SharedThreadLocalRandomInspectionTest.java @@ -0,0 +1,77 @@ +/* + * 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. + * 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.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; + +/** + * @author Bas Leijdekkers + */ +public class SharedThreadLocalRandomInspectionTest extends LightInspectionTestCase { + @Override + protected InspectionProfileEntry getInspection() { + return new SharedThreadLocalRandomInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package java.util.concurrent;\n" + + "import java.util.Random;" + + "public class ThreadLocalRandom extends Random {" + + " public static ThreadLocalRandom current() {" + + " return null;" + + " }" + + "}" + }; + } + + public void testNoWarn() { + doStatementTest("System.out.println(java.util.concurrent.ThreadLocalRandom.current().nextInt());"); + } + + public void testArgument() { + doStatementTest("System.out.println(java.util.concurrent.ThreadLocalRandom./*'ThreadLocalRandom' instance might be shared between threads*/current/**/());"); + } + + public void testNoWarn2() { + doMemberTest("void m() {" + + " java.util.concurrent.ThreadLocalRandom r = java.util.concurrent.ThreadLocalRandom.current();" + + "}"); + } + + public void testNestedClass() { + doMemberTest("void m() {" + + " java.util.concurrent.ThreadLocalRandom r = java.util.concurrent.ThreadLocalRandom./*'ThreadLocalRandom' instance might be shared between threads*/current/**/();" + + " class Z extends Thread {" + + " public void run() {" + + " System.out.println(r.nextInt(1));" + + " }" + + " }" + + "}"); + } + + public void testAssignmentToField() { + doTest("import java.util.concurrent.ThreadLocalRandom;" + + "class A {" + + " private ThreadLocalRandom r;" + + " void m() {" + + " r = ThreadLocalRandom./*'ThreadLocalRandom' instance might be shared between threads*/current/**/();" + + " }" + + "}"); + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionTest.java new file mode 100644 index 000000000000..e7c3b75f1a6d --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionTest.java @@ -0,0 +1,48 @@ +/* + * 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. + * 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.siyeh.ig.visibility; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; + +/** + * @author Bas Leijdekkers + */ +public class LambdaParameterHidingMemberVariableInspectionTest extends LightInspectionTestCase { + @Override + protected InspectionProfileEntry getInspection() { + return new LambdaParameterHidingMemberVariableInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] {"package java.util.function;" + + "public interface Function<T, R> {" + + " R apply(T t);" + + "}"}; + } + + public void testSimple() { + doTest("import java.util.function.Function;" + + "class X {" + + " private String s;" + + "" + + " void m() {" + + " Function<String, String> f = (/*Lambda parameter 's' hides field in class 'X'*/s/**/) -> null;" + + " }" + + "}"); + } +} diff --git a/plugins/IntelliLang/src/META-INF/plugin.xml b/plugins/IntelliLang/src/META-INF/plugin.xml index 34731356c845..b62e139cc20e 100644 --- a/plugins/IntelliLang/src/META-INF/plugin.xml +++ b/plugins/IntelliLang/src/META-INF/plugin.xml @@ -2,7 +2,19 @@ <name>IntelliLang</name> <id>org.intellij.intelliLang</id> <vendor>JetBrains</vendor> - <description><![CDATA[User configurable language injection support (originally developed by Sascha Weinreuter sascha.weinreuter@cit.de)]]></description> + <description> + <![CDATA[ + Enables user configurable language injection support (originally developed by Sascha Weinreuter sascha.weinreuter@cit.de) + The following features are available: + <ul> + <li>Language injection</li> + <li>Pattern validation</li> + <li>Regular expression support</li> + <li>Language Injections page in the Settings/Preferences dialog.</li> + <li>Ability to edit injected code in the special scratch-pad editor.</l> + </ul> + ]]> + </description> <version>8.0</version> <depends optional="true" config-file="intellilang-xpath-support.xml">XPathView</depends> diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/BaseBracesIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/BaseBracesIntention.java index 9b1e57afe720..ecaa8acad5cf 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/BaseBracesIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/BaseBracesIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.siyeh.ipp.braces; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ipp.base.MutablyNamedIntention; @@ -57,59 +56,21 @@ public abstract class BaseBracesIntention extends MutablyNamedIntention { final PsiElement parent = element.getParent(); if (parent instanceof PsiIfStatement) { final PsiIfStatement ifStatement = (PsiIfStatement)parent; - if (isBetweenThen(ifStatement, element)) { - return ifStatement.getThenBranch(); - } - - if (isBetweenElse(ifStatement, element)) { + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final int offset = element.getTextOffset(); + if (thenBranch != null && offset > thenBranch.getTextOffset()) { + final PsiKeyword elseElement = ifStatement.getElseElement(); + if (elseElement == null || offset < elseElement.getTextOffset()) { + // no 'else' branch or after 'then' branch but before 'else' keyword + return null; + } return ifStatement.getElseBranch(); } + return thenBranch; } - if (parent instanceof PsiWhileStatement) { - return ((PsiWhileStatement)parent).getBody(); - } - if (parent instanceof PsiDoWhileStatement) { - return ((PsiDoWhileStatement)parent).getBody(); - } - if (parent instanceof PsiForStatement) { - return ((PsiForStatement)parent).getBody(); - } - if (parent instanceof PsiForeachStatement) { - return ((PsiForeachStatement)parent).getBody(); + if (parent instanceof PsiLoopStatement) { + return ((PsiLoopStatement)parent).getBody(); } return null; } - - private static boolean isBetweenThen(@NotNull PsiIfStatement ifStatement, @NotNull PsiElement element) { - final PsiElement rParenth = ifStatement.getRParenth(); - final PsiElement elseElement = ifStatement.getElseElement(); - - if (rParenth == null) { - return false; - } - - if (elseElement == null) { - return true; - } - - final TextRange rParenthTextRangeTextRange = rParenth.getTextRange(); - final TextRange elseElementTextRange = elseElement.getTextRange(); - final TextRange elementTextRange = element.getTextRange(); - - return new TextRange(rParenthTextRangeTextRange.getEndOffset(), elseElementTextRange.getStartOffset()).contains(elementTextRange); - } - - private static boolean isBetweenElse(@NotNull PsiIfStatement ifStatement, @NotNull PsiElement element) { - final PsiElement elseElement = ifStatement.getElseElement(); - - if (elseElement == null) { - return false; - } - - final TextRange ifStatementTextRange = ifStatement.getTextRange(); - final TextRange elseElementTextRange = elseElement.getTextRange(); - final TextRange elementTextRange = element.getTextRange(); - - return new TextRange(elseElementTextRange.getStartOffset(), ifStatementTextRange.getEndOffset()).contains(elementTextRange); - } } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitMultiCatchIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitMultiCatchIntention.java index f0288078a691..c58edc18b433 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitMultiCatchIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitMultiCatchIntention.java @@ -17,12 +17,15 @@ package com.siyeh.ipp.exceptions; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; -import static com.intellij.psi.PsiAnnotation.TargetType; +import java.util.List; + +import static com.intellij.util.ObjectUtils.assertNotNull; public class SplitMultiCatchIntention extends Intention { @@ -52,25 +55,28 @@ public class SplitMultiCatchIntention extends Intention { return; } - final PsiModifierList modifierList = parameter.getModifierList(); - if (modifierList != null) { - for (PsiAnnotation annotation : modifierList.getAnnotations()) { - if (PsiImplUtil.findApplicableTarget(annotation, TargetType.TYPE_USE) == TargetType.TYPE_USE) { - annotation.delete(); - } - } - } - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject()); - for (PsiType disjunction : ((PsiDisjunctionType)type).getDisjunctions()) { + final List<PsiTypeElement> disjunctions = PsiTreeUtil.getChildrenOfTypeAsList(parameter.getTypeElement(), PsiTypeElement.class); + for (int i = 0; i < disjunctions.size(); i++) { final PsiCatchSection copy = (PsiCatchSection)catchSection.copy(); - final PsiParameter copyParameter = copy.getParameter(); - assert copyParameter != null : copy.getText(); - final PsiTypeElement typeElement = copyParameter.getTypeElement(); - assert typeElement != null : copyParameter.getText(); - final PsiTypeElement newTypeElement = factory.createTypeElement(disjunction); + + final PsiTypeElement typeElement = assertNotNull(assertNotNull(copy.getParameter()).getTypeElement()); + final PsiTypeElement newTypeElement = factory.createTypeElementFromText(disjunctions.get(i).getText(), catchSection); typeElement.replace(newTypeElement); + grandParent.addBefore(copy, catchSection); + + if (i == 0) { + // clear the original from type annotations: they belong to the first disjunction and should not appear in others + final PsiModifierList modifierList = parameter.getModifierList(); + if (modifierList != null) { + for (PsiAnnotation annotation : modifierList.getAnnotations()) { + if (PsiImplUtil.findApplicableTarget(annotation, PsiAnnotation.TargetType.TYPE_USE) == PsiAnnotation.TargetType.TYPE_USE) { + annotation.delete(); + } + } + } + } } catchSection.delete(); diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReverseForLoopDirectionIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReverseForLoopDirectionIntention.java index 35404ae2f77d..d76eaaffc86c 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReverseForLoopDirectionIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReverseForLoopDirectionIntention.java @@ -22,9 +22,9 @@ import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.psiutils.ComparisonUtils; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; -import com.siyeh.ipp.psiutils.VariableAccessUtils; import org.jetbrains.annotations.NotNull; public class ReverseForLoopDirectionIntention extends Intention { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReverseForLoopDirectionPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReverseForLoopDirectionPredicate.java index f37d90013490..ef8b6d73093c 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReverseForLoopDirectionPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReverseForLoopDirectionPredicate.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2013 Bas Leijdekkers + * Copyright 2009-2014 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,14 @@ */ package com.siyeh.ipp.forloop; +import com.siyeh.ig.psiutils.ComparisonUtils; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; import com.siyeh.ipp.base.PsiElementPredicate; -import com.siyeh.ipp.psiutils.VariableAccessUtils; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; class ReverseForLoopDirectionPredicate implements PsiElementPredicate { @@ -57,11 +61,109 @@ class ReverseForLoopDirectionPredicate implements PsiElementPredicate { return false; } final PsiExpression condition = forStatement.getCondition(); - if (!VariableAccessUtils.isVariableCompared(variable, condition)) { + if (!isVariableCompared(variable, condition)) { return false; } final PsiStatement update = forStatement.getUpdate(); - return VariableAccessUtils.isVariableIncrementOrDecremented(variable, - update); + return isVariableIncrementOrDecremented(variable, update); + } + + public static boolean isVariableCompared( + @NotNull PsiVariable variable, @Nullable PsiExpression expression) { + if (!(expression instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression binaryExpression = + (PsiBinaryExpression)expression; + final IElementType tokenType = binaryExpression.getOperationTokenType(); + if (!ComparisonUtils.isComparisonOperation(tokenType)) { + return false; + } + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + if (rhs == null) { + return false; + } + if (VariableAccessUtils.evaluatesToVariable(lhs, variable)) { + return true; + } + else if (VariableAccessUtils.evaluatesToVariable(rhs, variable)) { + return true; + } + return false; + } + + public static boolean isVariableIncrementOrDecremented( + @NotNull PsiVariable variable, @Nullable PsiStatement statement) { + if (!(statement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpressionStatement expressionStatement = + (PsiExpressionStatement)statement; + PsiExpression expression = expressionStatement.getExpression(); + expression = ParenthesesUtils.stripParentheses(expression); + if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = + (PsiPrefixExpression)expression; + final IElementType tokenType = prefixExpression.getOperationTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS) && + !tokenType.equals(JavaTokenType.MINUSMINUS)) { + return false; + } + final PsiExpression operand = prefixExpression.getOperand(); + return VariableAccessUtils.evaluatesToVariable(operand, variable); + } + else if (expression instanceof PsiPostfixExpression) { + final PsiPostfixExpression postfixExpression = + (PsiPostfixExpression)expression; + final IElementType tokenType = postfixExpression.getOperationTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS) && + !tokenType.equals(JavaTokenType.MINUSMINUS)) { + return false; + } + final PsiExpression operand = postfixExpression.getOperand(); + return VariableAccessUtils.evaluatesToVariable(operand, variable); + } + else if (expression instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression assignmentExpression = + (PsiAssignmentExpression)expression; + final IElementType tokenType = + assignmentExpression.getOperationTokenType(); + PsiExpression lhs = assignmentExpression.getLExpression(); + lhs = ParenthesesUtils.stripParentheses(lhs); + if (!VariableAccessUtils.evaluatesToVariable(lhs, variable)) { + return false; + } + PsiExpression rhs = assignmentExpression.getRExpression(); + rhs = ParenthesesUtils.stripParentheses(rhs); + if (tokenType == JavaTokenType.EQ) { + if (!(rhs instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression binaryExpression = + (PsiBinaryExpression)rhs; + final IElementType token = + binaryExpression.getOperationTokenType(); + if (!token.equals(JavaTokenType.PLUS) && + !token.equals(JavaTokenType.MINUS)) { + return false; + } + PsiExpression lOperand = binaryExpression.getLOperand(); + lOperand = ParenthesesUtils.stripParentheses(lOperand); + PsiExpression rOperand = binaryExpression.getROperand(); + rOperand = ParenthesesUtils.stripParentheses(rOperand); + if (VariableAccessUtils.evaluatesToVariable(rOperand, variable)) { + return true; + } + else if (VariableAccessUtils.evaluatesToVariable(lOperand, variable)) { + return true; + } + } + else if (tokenType == JavaTokenType.PLUSEQ || + tokenType == JavaTokenType.MINUSEQ) { + return true; + } + } + return false; } }
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceAssignmentWithPostfixExpressionPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceAssignmentWithPostfixExpressionPredicate.java index e239e85893af..89cd997e6822 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceAssignmentWithPostfixExpressionPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceAssignmentWithPostfixExpressionPredicate.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2013 Bas Leijdekkers + * Copyright 2009-2014 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,8 @@ package com.siyeh.ipp.opassign; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; import com.siyeh.ipp.base.PsiElementPredicate; -import com.siyeh.ipp.psiutils.VariableAccessUtils; class ReplaceAssignmentWithPostfixExpressionPredicate implements PsiElementPredicate { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceableWithOperatorAssignmentPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceableWithOperatorAssignmentPredicate.java index 959c858c05f0..34a2d0851d24 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceableWithOperatorAssignmentPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceableWithOperatorAssignmentPredicate.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,10 @@ package com.siyeh.ipp.opassign; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiUtil; -import com.siyeh.ipp.base.PsiElementPredicate; import com.siyeh.ig.psiutils.EquivalenceChecker; +import com.siyeh.ig.psiutils.SideEffectChecker; +import com.siyeh.ipp.base.PsiElementPredicate; import com.siyeh.ipp.psiutils.ErrorUtil; -import com.siyeh.ipp.psiutils.SideEffectChecker; class ReplaceableWithOperatorAssignmentPredicate implements PsiElementPredicate { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ConditionalUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ConditionalUtils.java deleted file mode 100644 index 8d13fe20bee8..000000000000 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ConditionalUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers - * - * 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.siyeh.ipp.psiutils; - -import com.intellij.psi.*; -import org.jetbrains.annotations.NonNls; - -public class ConditionalUtils { - - private ConditionalUtils() {} - - public static boolean isReturn(PsiStatement statement, - @NonNls String value) { - if (statement == null) { - return false; - } - if (!(statement instanceof PsiReturnStatement)) { - return false; - } - final PsiReturnStatement returnStatement = - (PsiReturnStatement)statement; - if (returnStatement.getReturnValue() == null) { - return false; - } - final PsiExpression returnValue = returnStatement.getReturnValue(); - if (returnValue == null) { - return false; - } - final String returnValueText = returnValue.getText(); - return value.equals(returnValueText); - } - - public static boolean isAssignment(PsiStatement statement, - @NonNls String value) { - if (statement == null) { - return false; - } - if (!(statement instanceof PsiExpressionStatement)) { - return false; - } - final PsiExpressionStatement expressionStatement = - (PsiExpressionStatement)statement; - final PsiExpression expression = expressionStatement.getExpression(); - if (!(expression instanceof PsiAssignmentExpression)) { - return false; - } - final PsiAssignmentExpression assignment = - (PsiAssignmentExpression)expression; - final PsiExpression rhs = assignment.getRExpression(); - if (rhs == null) { - return false; - } - final String rhsText = rhs.getText(); - return value.equals(rhsText); - } -} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ControlFlowUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ControlFlowUtils.java deleted file mode 100644 index 668444bd22c1..000000000000 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ControlFlowUtils.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers - * - * 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.siyeh.ipp.psiutils; - -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; - -public class ControlFlowUtils { - - private ControlFlowUtils() { - } - - public static boolean statementMayCompleteNormally(PsiStatement statement) { - if (statement instanceof PsiBreakStatement || - statement instanceof PsiContinueStatement || - statement instanceof PsiReturnStatement || - statement instanceof PsiThrowStatement) { - return false; - } - else if (statement instanceof PsiExpressionListStatement || - statement instanceof PsiExpressionStatement || - statement instanceof PsiEmptyStatement || - statement instanceof PsiAssertStatement || - statement instanceof PsiDeclarationStatement) { - return true; - } - else if (statement instanceof PsiForStatement) { - final PsiForStatement loopStatement = (PsiForStatement)statement; - final PsiExpression test = loopStatement.getCondition(); - return test != null && !isBooleanConstant(test, true) || - statementIsBreakTarget(loopStatement); - } - else if (statement instanceof PsiForeachStatement) { - return true; - } - else if (statement instanceof PsiWhileStatement) { - final PsiWhileStatement loopStatement = - (PsiWhileStatement)statement; - final PsiExpression test = loopStatement.getCondition(); - return !isBooleanConstant(test, true) - || statementIsBreakTarget(loopStatement); - } - else if (statement instanceof PsiDoWhileStatement) { - final PsiDoWhileStatement loopStatement = - (PsiDoWhileStatement)statement; - final PsiExpression test = loopStatement.getCondition(); - final PsiStatement body = loopStatement.getBody(); - return statementMayCompleteNormally(body) && - !isBooleanConstant(test, true) - || statementIsBreakTarget(loopStatement); - } - else if (statement instanceof PsiSynchronizedStatement) { - final PsiCodeBlock body = - ((PsiSynchronizedStatement)statement).getBody(); - return codeBlockMayCompleteNormally(body); - } - else if (statement instanceof PsiBlockStatement) { - final PsiCodeBlock codeBlock = - ((PsiBlockStatement)statement).getCodeBlock(); - return codeBlockMayCompleteNormally(codeBlock); - } - else if (statement instanceof PsiLabeledStatement) { - final PsiLabeledStatement labeledStatement = - (PsiLabeledStatement)statement; - final PsiStatement body = labeledStatement.getStatement(); - return statementMayCompleteNormally(body) - || statementIsBreakTarget(body); - } - else if (statement instanceof PsiIfStatement) { - final PsiIfStatement ifStatement = (PsiIfStatement)statement; - final PsiStatement thenBranch = ifStatement.getThenBranch(); - if (statementMayCompleteNormally(thenBranch)) { - return true; - } - final PsiStatement elseBranch = ifStatement.getElseBranch(); - return elseBranch == null || - statementMayCompleteNormally(elseBranch); - } - else if (statement instanceof PsiTryStatement) { - final PsiTryStatement tryStatement = (PsiTryStatement)statement; - - final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); - if (finallyBlock != null) { - if (!codeBlockMayCompleteNormally(finallyBlock)) { - return false; - } - } - final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); - if (codeBlockMayCompleteNormally(tryBlock)) { - return true; - } - final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); - for (final PsiCodeBlock catchBlock : catchBlocks) { - if (codeBlockMayCompleteNormally(catchBlock)) { - return true; - } - } - return false; - } - else if (statement instanceof PsiSwitchStatement) { - final PsiSwitchStatement switchStatement = - (PsiSwitchStatement)statement; - if (statementIsBreakTarget(switchStatement)) { - return true; - } - final PsiCodeBlock body = switchStatement.getBody(); - if (body == null) { - return true; - } - final PsiStatement[] statements = body.getStatements(); - int lastNonLabelOffset = -1; - final int lastStatementIndex = statements.length - 1; - for (int i = lastStatementIndex; i >= 0; i--) { - if (!(statements[i] instanceof PsiSwitchLabelStatement)) { - lastNonLabelOffset = i; - break; - } - } - if (lastNonLabelOffset == -1) { - return true; // it's all labels - } - else if (lastNonLabelOffset == lastStatementIndex) { - return statementMayCompleteNormally( - statements[lastStatementIndex]); - } - else { - return true; // the last statement is a label - } - } - else { - return false; - } - } - - private static boolean codeBlockMayCompleteNormally(PsiCodeBlock block) { - if (block == null) { - return true; - } - final PsiStatement[] statements = block.getStatements(); - for (final PsiStatement statement : statements) { - if (!statementMayCompleteNormally(statement)) { - return false; - } - } - return true; - } - - private static boolean isBooleanConstant(PsiExpression expression, - boolean b) { - if (expression == null) { - return false; - } - final Project project = expression.getProject(); - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); - final PsiConstantEvaluationHelper constantEvaluationHelper = - psiFacade.getConstantEvaluationHelper(); - final Object value = - constantEvaluationHelper.computeConstantExpression - (expression, false); - if (!(value instanceof Boolean)) { - return false; - } - final Boolean aBoolean = (Boolean)value; - return aBoolean.booleanValue() == b; - } - - private static boolean statementIsBreakTarget(PsiStatement statement) { - if (statement == null) { - return false; - } - final BreakTargetFinder breakFinder = new BreakTargetFinder(statement); - statement.accept(breakFinder); - return breakFinder.breakFound(); - } - - public static boolean statementContainsNakedBreak(PsiStatement statement) { - if (statement == null) { - return false; - } - final NakedBreakFinder breakFinder = new NakedBreakFinder(); - statement.accept(breakFinder); - return breakFinder.breakFound(); - } - - private static class BreakTargetFinder - extends JavaRecursiveElementWalkingVisitor { - - private boolean m_found = false; - private final PsiStatement m_target; - - private BreakTargetFinder(PsiStatement target) { - m_target = target; - } - - public boolean breakFound() { - return m_found; - } - - @Override - public void visitElement(PsiElement element) { - if (m_found) { - return; - } - super.visitElement(element); - } - - @Override - public void visitReferenceExpression( - PsiReferenceExpression expression) { - } - - @Override - public void visitBreakStatement(PsiBreakStatement statement) { - super.visitBreakStatement(statement); - final PsiStatement exitedStatement = - statement.findExitedStatement(); - if (exitedStatement == null) { - return; - } - if (exitedStatement.equals(m_target)) { - m_found = true; - } - } - } - - private static class NakedBreakFinder - extends JavaRecursiveElementWalkingVisitor { - - private boolean m_found = false; - - public boolean breakFound() { - return m_found; - } - - @Override - public void visitElement(PsiElement element) { - if (m_found) { - return; - } - super.visitElement(element); - } - - @Override - public void visitReferenceExpression( - PsiReferenceExpression expression) { - } - - @Override - public void visitBreakStatement(PsiBreakStatement statement) { - if (statement.getLabelIdentifier() != null) { - return; - } - m_found = true; - } - - @Override - public void visitDoWhileStatement( - PsiDoWhileStatement statement) { - // don't drill down - } - - @Override - public void visitForStatement(PsiForStatement statement) { - // don't drill down - } - - @Override - public void visitForeachStatement(PsiForeachStatement statement) { - // don't drill down - } - - @Override - public void visitWhileStatement(PsiWhileStatement statement) { - // don't drill down - } - - @Override - public void visitSwitchStatement( - PsiSwitchStatement statement) { - // don't drill down - } - } -}
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/SideEffectChecker.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/SideEffectChecker.java deleted file mode 100644 index 7940dd739ecb..000000000000 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/SideEffectChecker.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2003-2005 Dave Griffith - * - * 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.siyeh.ipp.psiutils; - -import com.intellij.psi.*; -import com.intellij.psi.tree.IElementType; - -public class SideEffectChecker { - - private SideEffectChecker() { - super(); - } - - public static boolean mayHaveSideEffects(PsiExpression exp) { - final SideEffectsVisitor visitor = new SideEffectsVisitor(); - exp.accept(visitor); - return visitor.mayHaveSideEffects(); - } - - private static class SideEffectsVisitor extends JavaRecursiveElementWalkingVisitor { - - private boolean mayHaveSideEffects = false; - - @Override - public void visitElement(PsiElement element) { - if (!mayHaveSideEffects) { - super.visitElement(element); - } - } - - @Override - public void visitMethodCallExpression( - PsiMethodCallExpression expression) { - mayHaveSideEffects = true; - } - - @Override - public void visitNewExpression(PsiNewExpression expression) { - mayHaveSideEffects = true; - } - - @Override - public void visitAssignmentExpression( - PsiAssignmentExpression expression) { - mayHaveSideEffects = true; - } - - @Override - public void visitPrefixExpression(PsiPrefixExpression expression) { - super.visitPrefixExpression(expression); - final IElementType tokenType = expression.getOperationTokenType(); - - if (tokenType.equals(JavaTokenType.PLUSPLUS) || - tokenType.equals(JavaTokenType.MINUSMINUS)) { - mayHaveSideEffects = true; - } - } - - @Override - public void visitPostfixExpression(PsiPostfixExpression expression) { - super.visitPostfixExpression(expression); - final IElementType tokenType = expression.getOperationTokenType(); - - if (tokenType.equals(JavaTokenType.PLUSPLUS) || - tokenType.equals(JavaTokenType.MINUSMINUS)) { - mayHaveSideEffects = true; - } - } - - public boolean mayHaveSideEffects() { - return mayHaveSideEffects; - } - } -}
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/VariableAccessUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/VariableAccessUtils.java deleted file mode 100644 index 2ac8500bad4a..000000000000 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/VariableAccessUtils.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2009-2014 Bas Leijdekkers - * - * 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.siyeh.ipp.psiutils; - -import com.intellij.psi.*; -import com.intellij.psi.tree.IElementType; -import com.siyeh.ig.psiutils.ComparisonUtils; -import com.siyeh.ig.psiutils.ParenthesesUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -public class VariableAccessUtils { - - private VariableAccessUtils() { - } - - public static boolean isVariableCompared( - @NotNull PsiVariable variable, @Nullable PsiExpression expression) { - if (!(expression instanceof PsiBinaryExpression)) { - return false; - } - final PsiBinaryExpression binaryExpression = - (PsiBinaryExpression)expression; - final IElementType tokenType = binaryExpression.getOperationTokenType(); - if (!ComparisonUtils.isComparisonOperation(tokenType)) { - return false; - } - final PsiExpression lhs = binaryExpression.getLOperand(); - final PsiExpression rhs = binaryExpression.getROperand(); - if (rhs == null) { - return false; - } - if (evaluatesToVariable(lhs, variable)) { - return true; - } - else if (evaluatesToVariable(rhs, variable)) { - return true; - } - return false; - } - - public static boolean isVariableIncrementOrDecremented( - @NotNull PsiVariable variable, @Nullable PsiStatement statement) { - if (!(statement instanceof PsiExpressionStatement)) { - return false; - } - final PsiExpressionStatement expressionStatement = - (PsiExpressionStatement)statement; - PsiExpression expression = expressionStatement.getExpression(); - expression = ParenthesesUtils.stripParentheses(expression); - if (expression instanceof PsiPrefixExpression) { - final PsiPrefixExpression prefixExpression = - (PsiPrefixExpression)expression; - final IElementType tokenType = prefixExpression.getOperationTokenType(); - if (!tokenType.equals(JavaTokenType.PLUSPLUS) && - !tokenType.equals(JavaTokenType.MINUSMINUS)) { - return false; - } - final PsiExpression operand = prefixExpression.getOperand(); - return evaluatesToVariable(operand, variable); - } - else if (expression instanceof PsiPostfixExpression) { - final PsiPostfixExpression postfixExpression = - (PsiPostfixExpression)expression; - final IElementType tokenType = postfixExpression.getOperationTokenType(); - if (!tokenType.equals(JavaTokenType.PLUSPLUS) && - !tokenType.equals(JavaTokenType.MINUSMINUS)) { - return false; - } - final PsiExpression operand = postfixExpression.getOperand(); - return evaluatesToVariable(operand, variable); - } - else if (expression instanceof PsiAssignmentExpression) { - final PsiAssignmentExpression assignmentExpression = - (PsiAssignmentExpression)expression; - final IElementType tokenType = - assignmentExpression.getOperationTokenType(); - PsiExpression lhs = assignmentExpression.getLExpression(); - lhs = ParenthesesUtils.stripParentheses(lhs); - if (!evaluatesToVariable(lhs, variable)) { - return false; - } - PsiExpression rhs = assignmentExpression.getRExpression(); - rhs = ParenthesesUtils.stripParentheses(rhs); - if (tokenType == JavaTokenType.EQ) { - if (!(rhs instanceof PsiBinaryExpression)) { - return false; - } - final PsiBinaryExpression binaryExpression = - (PsiBinaryExpression)rhs; - final IElementType token = - binaryExpression.getOperationTokenType(); - if (!token.equals(JavaTokenType.PLUS) && - !token.equals(JavaTokenType.MINUS)) { - return false; - } - PsiExpression lOperand = binaryExpression.getLOperand(); - lOperand = ParenthesesUtils.stripParentheses(lOperand); - PsiExpression rOperand = binaryExpression.getROperand(); - rOperand = ParenthesesUtils.stripParentheses(rOperand); - if (evaluatesToVariable(rOperand, variable)) { - return true; - } - else if (evaluatesToVariable(lOperand, variable)) { - return true; - } - } - else if (tokenType == JavaTokenType.PLUSEQ || - tokenType == JavaTokenType.MINUSEQ) { - return true; - } - } - return false; - } - - public static boolean evaluatesToVariable( - @Nullable PsiExpression expression, - @NotNull PsiVariable variable) { - final PsiExpression strippedExpression = - ParenthesesUtils.stripParentheses(expression); - if (strippedExpression == null) { - return false; - } - if (!(expression instanceof PsiReferenceExpression)) { - return false; - } - final PsiReferenceExpression referenceExpression = - (PsiReferenceExpression)expression; - final PsiElement referent = referenceExpression.resolve(); - return variable.equals(referent); - } - - public static boolean isAnyVariableAssigned( - @NotNull Collection<PsiVariable> variables, - @Nullable PsiElement context) { - if (context == null) { - return false; - } - final VariableAssignedVisitor visitor = - new VariableAssignedVisitor(variables, true); - context.accept(visitor); - return visitor.isAssigned(); - } - - public static Set<PsiVariable> collectUsedVariables( - PsiElement context) { - if (context == null) { - return Collections.emptySet(); - } - final VariableCollectingVisitor visitor = - new VariableCollectingVisitor(); - context.accept(visitor); - return visitor.getUsedVariables(); - } - - private static class VariableCollectingVisitor - extends JavaRecursiveElementVisitor { - - private final Set<PsiVariable> usedVariables = new HashSet(); - - @Override - public void visitReferenceExpression( - PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement target = expression.resolve(); - if (!(target instanceof PsiVariable)) { - return; - } - final PsiVariable variable = (PsiVariable)target; - usedVariables.add(variable); - } - - public Set<PsiVariable> getUsedVariables() { - return usedVariables; - } - } -} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/VariableAssignedVisitor.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/VariableAssignedVisitor.java deleted file mode 100644 index 8352febe9861..000000000000 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/VariableAssignedVisitor.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers - * - * 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.siyeh.ipp.psiutils; - -import com.intellij.psi.*; -import com.intellij.psi.tree.IElementType; -import com.siyeh.ig.psiutils.ParenthesesUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; - -class VariableAssignedVisitor extends JavaRecursiveElementVisitor { - - @NotNull private final Collection<PsiVariable> variables; - private final boolean recurseIntoClasses; - private boolean assigned = false; - - public VariableAssignedVisitor(@NotNull Collection<PsiVariable> variables, - boolean recurseIntoClasses) { - this.variables = variables; - this.recurseIntoClasses = recurseIntoClasses; - } - - @Override - public void visitElement(@NotNull PsiElement element) { - if (assigned) { - return; - } - super.visitElement(element); - } - - @Override - public void visitAssignmentExpression( - @NotNull PsiAssignmentExpression assignment) { - if (assigned) { - return; - } - super.visitAssignmentExpression(assignment); - final PsiExpression lhs = assignment.getLExpression(); - for (PsiVariable variable : variables) { - if (mayEvaluateToVariable(lhs, variable)) { - assigned = true; - } - } - } - - @Override - public void visitClass(PsiClass aClass) { - if (!recurseIntoClasses) { - return; - } - if (assigned) { - return; - } - super.visitClass(aClass); - } - - @Override - public void visitPrefixExpression( - @NotNull PsiPrefixExpression prefixExpression) { - if (assigned) { - return; - } - super.visitPrefixExpression(prefixExpression); - final IElementType tokenType = prefixExpression.getOperationTokenType(); - if (!tokenType.equals(JavaTokenType.PLUSPLUS) && - !tokenType.equals(JavaTokenType.MINUSMINUS)) { - return; - } - final PsiExpression operand = prefixExpression.getOperand(); - for (PsiVariable variable : variables) { - if (mayEvaluateToVariable(operand, variable)) { - assigned = true; - } - } - } - - @Override - public void visitPostfixExpression( - @NotNull PsiPostfixExpression postfixExpression) { - if (assigned) { - return; - } - super.visitPostfixExpression(postfixExpression); - final IElementType tokenType = postfixExpression.getOperationTokenType(); - if (!tokenType.equals(JavaTokenType.PLUSPLUS) && - !tokenType.equals(JavaTokenType.MINUSMINUS)) { - return; - } - final PsiExpression operand = postfixExpression.getOperand(); - for (PsiVariable variable : variables) { - if (mayEvaluateToVariable(operand, variable)) { - assigned = true; - } - } - } - - public static boolean mayEvaluateToVariable( - @Nullable PsiExpression expression, - @NotNull PsiVariable variable) { - if (expression == null) { - return false; - } - if (expression instanceof PsiBinaryExpression) { - final PsiBinaryExpression binaryExpression = - (PsiBinaryExpression)expression; - final PsiExpression lOperand = binaryExpression.getLOperand(); - final PsiExpression rOperand = binaryExpression.getROperand(); - return mayEvaluateToVariable(lOperand, variable) || - mayEvaluateToVariable(rOperand, variable); - } - if (expression instanceof PsiParenthesizedExpression) { - final PsiParenthesizedExpression parenthesizedExpression = - (PsiParenthesizedExpression)expression; - final PsiExpression containedExpression = - parenthesizedExpression.getExpression(); - return mayEvaluateToVariable(containedExpression, variable); - } - if (expression instanceof PsiTypeCastExpression) { - final PsiTypeCastExpression typeCastExpression = - (PsiTypeCastExpression)expression; - final PsiExpression containedExpression = - typeCastExpression.getOperand(); - return mayEvaluateToVariable(containedExpression, variable); - } - if (expression instanceof PsiConditionalExpression) { - final PsiConditionalExpression conditional = - (PsiConditionalExpression)expression; - final PsiExpression thenExpression = conditional.getThenExpression(); - final PsiExpression elseExpression = conditional.getElseExpression(); - return mayEvaluateToVariable(thenExpression, variable) || - mayEvaluateToVariable(elseExpression, variable); - } - if (expression instanceof PsiArrayAccessExpression) { - final PsiElement parent = expression.getParent(); - if (parent instanceof PsiArrayAccessExpression) { - return false; - } - final PsiType type = variable.getType(); - if (!(type instanceof PsiArrayType)) { - return false; - } - final PsiArrayType arrayType = (PsiArrayType)type; - final int dimensions = arrayType.getArrayDimensions(); - if (dimensions <= 1) { - return false; - } - PsiArrayAccessExpression arrayAccessExpression = - (PsiArrayAccessExpression)expression; - PsiExpression arrayExpression = - arrayAccessExpression.getArrayExpression(); - int count = 1; - while (arrayExpression instanceof PsiArrayAccessExpression) { - arrayAccessExpression = - (PsiArrayAccessExpression)arrayExpression; - arrayExpression = arrayAccessExpression.getArrayExpression(); - count++; - } - return count != dimensions && - mayEvaluateToVariable(arrayExpression, variable); - } - return evaluatesToVariable(expression, variable); - } - - public static boolean evaluatesToVariable( - @Nullable PsiExpression expression, - @NotNull PsiVariable variable) { - final PsiExpression strippedExpression = - ParenthesesUtils.stripParentheses(expression); - if (strippedExpression == null) { - return false; - } - if (!(expression instanceof PsiReferenceExpression)) { - return false; - } - final PsiReferenceExpression referenceExpression = - (PsiReferenceExpression)expression; - final PsiElement referent = referenceExpression.resolve(); - return variable.equals(referent); - } - - public boolean isAssigned() { - return assigned; - } -}
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceIfWithSwitchIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceIfWithSwitchIntention.java index cde03e1aeb1c..9f40b4b36a13 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceIfWithSwitchIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceIfWithSwitchIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,12 +18,12 @@ package com.siyeh.ipp.switchtoif; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.psiutils.ControlFlowUtils; import com.siyeh.ig.psiutils.EquivalenceChecker; import com.siyeh.ig.psiutils.SwitchUtils; import com.siyeh.ig.psiutils.SwitchUtils.IfStatementBranch; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; -import com.siyeh.ipp.psiutils.ControlFlowUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrPredicate.java index b2c5aa87a3fb..3dfd039fec5c 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrPredicate.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,9 @@ package com.siyeh.ipp.trivialif; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.psiutils.ControlFlowUtils; import com.siyeh.ig.psiutils.EquivalenceChecker; import com.siyeh.ipp.base.PsiElementPredicate; -import com.siyeh.ipp.psiutils.ControlFlowUtils; import com.siyeh.ipp.psiutils.ErrorUtil; class MergeIfOrPredicate implements PsiElementPredicate { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeParallelIfsPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeParallelIfsPredicate.java index f2e889316400..57a78912c100 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeParallelIfsPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeParallelIfsPredicate.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +17,11 @@ package com.siyeh.ipp.trivialif; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.psiutils.ControlFlowUtils; import com.siyeh.ig.psiutils.EquivalenceChecker; +import com.siyeh.ig.psiutils.VariableAccessUtils; import com.siyeh.ipp.base.PsiElementPredicate; -import com.siyeh.ipp.psiutils.ControlFlowUtils; import com.siyeh.ipp.psiutils.ErrorUtil; -import com.siyeh.ipp.psiutils.VariableAccessUtils; import java.util.Collection; import java.util.HashSet; diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/BetweenIfAndElse.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/BetweenIfAndElse.java new file mode 100644 index 000000000000..00658098d56d --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/BetweenIfAndElse.java @@ -0,0 +1,10 @@ +class X { + { + if (true) { + System.out.println(); + } +<caret> else { + System.out.println(); + } + } +}
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse.java new file mode 100644 index 000000000000..29a595804f5c --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse.java @@ -0,0 +1,10 @@ +class X { + { + if (true) { + System.out.println(); + }<caret> + else { + System.out.println(); + } + } +}
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse2.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse2.java new file mode 100644 index 000000000000..9815cdf830e4 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse2.java @@ -0,0 +1,10 @@ +class X { + { + if<caret> (true) { + System.out.println(); + } + else { + System.out.println(); + } + } +}
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse2_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse2_after.java new file mode 100644 index 000000000000..feae02671942 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse2_after.java @@ -0,0 +1,8 @@ +class X { + { + if (true) System.out.println(); + else { + System.out.println(); + } + } +}
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse_after.java new file mode 100644 index 000000000000..feae02671942 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/braces/remove/IfElse_after.java @@ -0,0 +1,8 @@ +class X { + { + if (true) System.out.println(); + else { + System.out.println(); + } + } +}
\ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/braces/RemoveBracesIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/braces/RemoveBracesIntentionTest.java new file mode 100644 index 000000000000..74ebd04fe402 --- /dev/null +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/braces/RemoveBracesIntentionTest.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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.siyeh.ipp.braces; + +import com.siyeh.IntentionPowerPackBundle; +import com.siyeh.ipp.IPPTestCase; + +/** + * @see RemoveBracesIntention + * @author Bas Leijdekkers + */ +public class RemoveBracesIntentionTest extends IPPTestCase { + @Override + protected String getRelativePath() { + return "braces/remove"; + } + + @Override + protected String getIntentionName() { + return IntentionPowerPackBundle.message("remove.braces.intention.name", "if"); + } + + public void testBetweenIfAndElse() { assertIntentionNotAvailable(RemoveBracesIntention.class);} + public void testIfElse() { doTest(); } + public void testIfElse2() { doTest(); } +} diff --git a/plugins/ant/jps-plugin/ant-jps-plugin.iml b/plugins/ant/jps-plugin/ant-jps-plugin.iml index 976f684d067a..12aeb835539a 100644 --- a/plugins/ant/jps-plugin/ant-jps-plugin.iml +++ b/plugins/ant/jps-plugin/ant-jps-plugin.iml @@ -13,6 +13,7 @@ <orderEntry type="module" module-name="util" /> <orderEntry type="module" module-name="jps-builders" /> <orderEntry type="module" module-name="java-runtime" /> + <orderEntry type="module" module-name="jps-serialization-tests" scope="TEST" /> </component> </module> diff --git a/plugins/ant/src/com/intellij/lang/ant/AntImportsIndex.java b/plugins/ant/src/com/intellij/lang/ant/AntImportsIndex.java index be3dc676245b..6c8e413fae95 100644 --- a/plugins/ant/src/com/intellij/lang/ant/AntImportsIndex.java +++ b/plugins/ant/src/com/intellij/lang/ant/AntImportsIndex.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. @@ -98,11 +98,13 @@ public class AntImportsIndex extends ScalarIndexExtension<Integer>{ return DATA_INDEXER; } + @NotNull @Override public KeyDescriptor<Integer> getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML); diff --git a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/CvsBundle.properties b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/CvsBundle.properties index 89385066f85a..15ce261fa653 100644 --- a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/CvsBundle.properties +++ b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/CvsBundle.properties @@ -415,7 +415,6 @@ action.Cvs.ToggleOffline.text=_Work Offline action.Cvs.ToggleOffline.description=Toggle offline mode for CVS root containing selected file set.online.notification.text=Set to online mode set.offline.notification.text=Set to offline mode -plugin.CVS.description=Provides integration with CVS version control system adding.cvsignore.files.to.cvs.action.name=Adding .cvsignore Files to CVS browse.repository.operation.name=Browse Repository configure.global.cvs.settings.action.name=Configure Global CVS Settings diff --git a/plugins/cvs/cvs-plugin/src/META-INF/plugin.xml b/plugins/cvs/cvs-plugin/src/META-INF/plugin.xml index 20f34c5513b0..1cefc9748ae4 100644 --- a/plugins/cvs/cvs-plugin/src/META-INF/plugin.xml +++ b/plugins/cvs/cvs-plugin/src/META-INF/plugin.xml @@ -5,6 +5,17 @@ <vendor>JetBrains</vendor> <resource-bundle>com.intellij.cvsSupport2.CvsBundle</resource-bundle> <category>VCS Integration</category> + <description> + <![CDATA[ + Allows working with CVS version control system. + The following features are available: + <ul> + <li>Dedicated page under the Version Control node in the Settings/Preferences dialog.</li> + <li>When CVS is not enabled, it is still possible to browse, check out sources from and import into the available CVS repositories.</li> + <li>When CVS is enabled, the CVS node appears on the VCS menu, and on the context menu of the editor. + </ul> + ]]> + </description> <depends>com.intellij.modules.lang</depends> <depends>com.intellij.modules.vcs</depends> diff --git a/plugins/devkit/jps-plugin/devkit-jps-plugin.iml b/plugins/devkit/jps-plugin/devkit-jps-plugin.iml index f88b075e0722..a80f7f38f339 100644 --- a/plugins/devkit/jps-plugin/devkit-jps-plugin.iml +++ b/plugins/devkit/jps-plugin/devkit-jps-plugin.iml @@ -12,6 +12,7 @@ <orderEntry type="module" module-name="jps-model-serialization" /> <orderEntry type="module" module-name="jps-builders" /> <orderEntry type="module" module-name="jps-model-impl" scope="TEST" /> + <orderEntry type="module" module-name="jps-serialization-tests" scope="TEST" /> </component> </module> diff --git a/plugins/devkit/src/references/IconsReferencesContributor.java b/plugins/devkit/src/references/IconsReferencesContributor.java index 74d258783660..eac85d8f0f3c 100644 --- a/plugins/devkit/src/references/IconsReferencesContributor.java +++ b/plugins/devkit/src/references/IconsReferencesContributor.java @@ -299,7 +299,7 @@ public class IconsReferencesContributor extends PsiReferenceContributor implemen model.setCaseSensitive(true); model.setFindAll(true); model.setWholeWordsOnly(true); - FindInProjectUtil.findUsages(model, FindInProjectUtil.getPsiDirectory(model, project), project, false, new Processor<UsageInfo>() { + FindInProjectUtil.findUsages(model, FindInProjectUtil.getPsiDirectory(model, project), project, new Processor<UsageInfo>() { @Override public boolean process(final UsageInfo usage) { ApplicationManager.getApplication().runReadAction(new Runnable() { diff --git a/plugins/eclipse/resources/META-INF/plugin.xml b/plugins/eclipse/resources/META-INF/plugin.xml index b3cd54debe52..a3f76504c14c 100644 --- a/plugins/eclipse/resources/META-INF/plugin.xml +++ b/plugins/eclipse/resources/META-INF/plugin.xml @@ -1,7 +1,20 @@ <idea-plugin> <name>Eclipse Integration</name> <id>org.jetbrains.idea.eclipse</id> - <description>Provides possibility to import, export and synchronize Eclipse project files</description> + <description> + <![CDATA[ + This plugin enables integration with Eclipse and provides the following features: + <ul> + <li>Open Eclipse project in IntelliJ IDEA</li> + <li>Import Eclipse project into IntelliJ IDEA</li> + <li>Export IntelliJ IDEA project into Eclipse</li> + <li>Convert IntelliJ IDEA module to Eclipse-compatible format</li> + <li>Synchronize Eclipse project files</li> + </ul> + <p/> + ]]> + </description> + <version>3.0</version> <vendor url="http://www.jetbrains.com" logo="/general/ijLogo.png">JetBrains s.r.o.</vendor> <extensions defaultExtensionNs="com.intellij"> diff --git a/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentChecker.java b/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentChecker.java index 155e7e2e2b78..df40458aa36b 100644 --- a/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentChecker.java +++ b/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentChecker.java @@ -16,7 +16,6 @@ package com.intellij.remoteServer.util; import com.intellij.execution.configurations.RuntimeConfigurationWarning; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; @@ -29,14 +28,11 @@ import com.intellij.remoteServer.configuration.ServerConfigurationBase; import com.intellij.remoteServer.configuration.deployment.DeploymentSource; import com.intellij.remoteServer.configuration.deployment.ModuleDeploymentSource; import git4idea.GitUtil; -import git4idea.commands.Git; -import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; import java.io.File; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.List; /** * @author michael.golubev @@ -47,21 +43,23 @@ public class CloudGitDeploymentChecker< SR extends CloudMultiSourceServerRuntimeInstance<T, ?, ?, ?>> { private GitRepositoryManager myGitRepositoryManager; - private Git myGit; private final DeploymentSource myDeploymentSource; private final RemoteServer<SC> myServer; private final CloudDeploymentNameEditor<T> mySettingsEditor; + private final CloudGitDeploymentDetector myDetector; public CloudGitDeploymentChecker(DeploymentSource deploymentSource, RemoteServer<SC> server, - CloudDeploymentNameEditor<T> settingsEditor) { + CloudDeploymentNameEditor<T> settingsEditor, + CloudGitDeploymentDetector detector) { myDeploymentSource = deploymentSource; myServer = server; mySettingsEditor = settingsEditor; + myDetector = detector; } - public void checkGitUrl(final T settings, Pattern gitUrlPattern) throws ConfigurationException { + public void checkGitUrl(final T settings) throws ConfigurationException { if (!(myDeploymentSource instanceof ModuleDeploymentSource)) { return; } @@ -82,12 +80,6 @@ public class CloudGitDeploymentChecker< if (myGitRepositoryManager == null) { myGitRepositoryManager = GitUtil.getRepositoryManager(project); } - if (myGit == null) { - myGit = ServiceManager.getService(Git.class); - if (myGit == null) { - return; - } - } VirtualFile contentRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(contentRootFile); if (contentRoot == null) { @@ -102,28 +94,11 @@ public class CloudGitDeploymentChecker< String expectedName = settings.getDeploymentSourceName(myDeploymentSource); - boolean unexpectedNameFound = false; - for (GitRemote remote : repository.getRemotes()) { - for (String url : remote.getUrls()) { - Matcher matcher = gitUrlPattern.matcher(url); - if (matcher.matches()) { - String matchedName = matcher.group(1); - if (matchedName.equals(expectedName)) { - return; - } - else { - unexpectedNameFound = true; - break; - } - } - } - } - - if (!unexpectedNameFound) { + List<String> appNames = myDetector.collectApplicationNames(repository); + if (appNames.isEmpty() || appNames.contains(expectedName)) { return; } - RuntimeConfigurationWarning warning = new RuntimeConfigurationWarning("Cloud Git URL found in repository, but it doesn't match the run configuration"); diff --git a/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentDetector.java b/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentDetector.java new file mode 100644 index 000000000000..f4fdd3fc5ae8 --- /dev/null +++ b/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentDetector.java @@ -0,0 +1,50 @@ +/* + * 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. + * 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.remoteServer.util; + +import git4idea.repo.GitRemote; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author michael.golubev + */ +public class CloudGitDeploymentDetector { + + private final Pattern myGitUrlPattern; + + public CloudGitDeploymentDetector(Pattern gitUrlPattern) { + myGitUrlPattern = gitUrlPattern; + } + + public List<String> collectApplicationNames(@NotNull GitRepository repository) { + List<String> result = new ArrayList<String>(); + for (GitRemote remote : repository.getRemotes()) { + for (String url : remote.getUrls()) { + Matcher matcher = myGitUrlPattern.matcher(url); + if (matcher.matches()) { + result.add(matcher.group(1)); + } + } + } + return result; + } +} diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index 5bd07d3b8883..8664c8ae51e2 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -1,7 +1,18 @@ <idea-plugin> <name>Git Integration</name> <id>Git4Idea</id> - <description>Provides integration with Git version control system</description> + <description> + <![CDATA[ + Allows working with <a href="http://git-scm.com/">Git version control system</a>. + The following features are available: + <ul> + <li>Dedicated page under the Version Control node in the Settings/Preferences dialog.</li> + <li>Ability to browse, check out sources from and import into the available Git repositories, when Git is not enabled.</li> + <li>When Git is enabled, the Git node appears on the VCS menu, and on the context menu of the editor.</li> + </ul> + <p>Numerous plugins depend on the Git Integration plugin.</p> + ]]> + </description> <version>8.1</version> <category>VCS Integration</category> <vendor url="http://svn.jetbrains.org/idea/Trunk/bundled/git4idea/" logo="/general/ijLogo.png">JetBrains</vendor> diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index d5c4b3fa8505..013d4cafe836 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -25,7 +25,10 @@ import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.*; +import com.intellij.openapi.vcs.CheckinProjectPanel; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.ObjectsConvertor; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.changes.ui.SelectFilePathsDialog; import com.intellij.openapi.vcs.checkin.CheckinChangeListSpecificComponent; @@ -33,7 +36,10 @@ import com.intellij.openapi.vcs.checkin.CheckinEnvironment; import com.intellij.openapi.vcs.ui.RefreshableOnComponent; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.GuiUtils; -import com.intellij.util.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.FunctionUtil; +import com.intellij.util.NullableFunction; +import com.intellij.util.PairConsumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; import com.intellij.util.ui.UIUtil; @@ -643,8 +649,8 @@ public class GitCheckinEnvironment implements CheckinEnvironment { @Override @NotNull - protected Set<VirtualFile> getRoots() { - return GitUtil.gitRoots(getSelectedFilePaths()); + protected Set<VirtualFile> getVcsRoots(@NotNull Collection<FilePath> filePaths) { + return GitUtil.gitRoots(filePaths); } @Nullable @@ -665,26 +671,18 @@ public class GitCheckinEnvironment implements CheckinEnvironment { return h.run(); } - @NotNull - private List<FilePath> getSelectedFilePaths() { - return ContainerUtil.map(myCheckinPanel.getFiles(), new Function<File, FilePath>() { - @Override - public FilePath fun(File file) { - return new FilePathImpl(file, file.isDirectory()); - } - }); - } - private List<String> getUsersList(final Project project) { return NewGitUsersComponent.getInstance(project).get(); } + @Override public void refresh() { super.refresh(); myAuthor.setSelectedItem(""); reset(); } + @Override public void saveState() { String author = (String)myAuthor.getEditor().getItem(); myNextCommitAuthor = author.length() == 0 ? null : author; @@ -699,6 +697,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { myNextCommitAuthorDate = myAuthorDate; } + @Override public void restoreState() { refresh(); } diff --git a/plugins/git4idea/src/git4idea/history/NewGitUsersComponent.java b/plugins/git4idea/src/git4idea/history/NewGitUsersComponent.java index 2afb3c821223..89ccaa51d195 100644 --- a/plugins/git4idea/src/git4idea/history/NewGitUsersComponent.java +++ b/plugins/git4idea/src/git4idea/history/NewGitUsersComponent.java @@ -1,9 +1,12 @@ /* - * Copyright 2000-2010 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. * 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. @@ -88,7 +91,7 @@ public class NewGitUsersComponent { private static class MyDataExternalizer implements DataExternalizer<List<String>> { @Override - public List<String> read(DataInput in) throws IOException { + public List<String> read(@NotNull DataInput in) throws IOException { final int size = in.readInt(); final ArrayList<String> result = new ArrayList<String>(size); for (int i = 0; i < size; i++) { @@ -98,7 +101,7 @@ public class NewGitUsersComponent { } @Override - public void save(DataOutput out, List<String> value) throws IOException { + public void save(@NotNull DataOutput out, List<String> value) throws IOException { out.writeInt(value.size()); for (String s : value) { out.writeUTF(s); diff --git a/plugins/git4idea/src/git4idea/history/wholeTree/GitCommitsSequentialIndex.java b/plugins/git4idea/src/git4idea/history/wholeTree/GitCommitsSequentialIndex.java index 70239c1b1a5d..0c69e45f6ae2 100644 --- a/plugins/git4idea/src/git4idea/history/wholeTree/GitCommitsSequentialIndex.java +++ b/plugins/git4idea/src/git4idea/history/wholeTree/GitCommitsSequentialIndex.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. @@ -39,6 +39,7 @@ import com.intellij.util.io.EnumeratorStringDescriptor; import git4idea.GitRevisionNumber; import git4idea.history.GitHistoryUtils; import git4idea.history.browser.SHAHash; +import org.jetbrains.annotations.NotNull; import java.io.*; import java.util.*; @@ -120,12 +121,12 @@ public class GitCommitsSequentialIndex implements GitCommitsSequentially { private DataExternalizer<String> createExternalizer() { return new DataExternalizer<String>() { @Override - public void save(DataOutput out, String value) throws IOException { + public void save(@NotNull DataOutput out, String value) throws IOException { out.writeUTF(value); } @Override - public String read(DataInput in) throws IOException { + public String read(@NotNull DataInput in) throws IOException { return in.readUTF(); } }; diff --git a/plugins/git4idea/tests/git4idea/tests/SkeletonBuilderTest.java b/plugins/git4idea/tests/git4idea/tests/SkeletonBuilderTest.java index aabf48c54fad..1417a118eacc 100644 --- a/plugins/git4idea/tests/git4idea/tests/SkeletonBuilderTest.java +++ b/plugins/git4idea/tests/git4idea/tests/SkeletonBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -789,6 +789,7 @@ public class SkeletonBuilderTest extends TestCase { return new MockVirtualFileSystem(); } + @NotNull @Override public String getPath() { return "mock"; diff --git a/plugins/github/src/META-INF/plugin.xml b/plugins/github/src/META-INF/plugin.xml index e0345633a81d..8baf48bf6eee 100644 --- a/plugins/github/src/META-INF/plugin.xml +++ b/plugins/github/src/META-INF/plugin.xml @@ -2,7 +2,17 @@ <name>GitHub</name> <id>org.jetbrains.plugins.github</id> <vendor>JetBrains</vendor> - <description>GitHub integration</description> + <description> + <![CDATA[ + Allows working with <a href="http://github.com/">GitHub</a>. + The following features are available: + <ul> + <li>Dedicated page under the Version Control node in the Settings/Preferences dialog.</li> + <li>Ability to browse, check out sources from and import into the available Git repositories, when GitHub is not enabled.</li> + <li>When GitHub is enabled, the GitHub node appears on the VCS menu, and on the context menu of the editor. + </ul> + ]]> + </description> <depends>com.intellij.modules.lang</depends> <depends>Git4Idea</depends> diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java index 878b9b855a0c..600f484f0c0b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vfs.VirtualFile; @@ -41,12 +42,14 @@ import org.jetbrains.plugins.github.api.GithubGist; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.ui.GithubCreateGistDialog; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import org.jetbrains.plugins.github.util.GithubNotifications; import org.jetbrains.plugins.github.util.GithubUtil; import java.io.IOException; -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import static org.jetbrains.plugins.github.api.GithubGist.FileContent; @@ -110,33 +113,24 @@ public class GithubCreateGistAction extends DumbAwareAction { return; } - GithubAuthData auth = GithubAuthData.createAnonymous(); - if (!dialog.isAnonymous()) { - try { - auth = getValidAuthData(project); - } - catch (GithubOperationCanceledException e) { - return; - } - catch (IOException e) { - GithubNotifications.showError(project, "Can't create gist", e); - return; - } + final GithubAuthDataHolder authHolder = getValidAuthData(project, dialog.isAnonymous()); + if (authHolder == null) { + return; } - final AtomicReference<String> url = new AtomicReference<String>(); - final GithubAuthData finalAuth = auth; + final Ref<String> url = new Ref<String>(); new Task.Backgroundable(project, "Creating Gist...") { @Override public void run(@NotNull ProgressIndicator indicator) { List<FileContent> contents = collectContents(project, editor, file, files); - String gistUrl = createGist(project, finalAuth, contents, dialog.isPrivate(), dialog.getDescription(), dialog.getFileName()); + String gistUrl = + createGist(project, authHolder, indicator, contents, dialog.isPrivate(), dialog.getDescription(), dialog.getFileName()); url.set(gistUrl); } @Override public void onSuccess() { - if (url.get() == null) { + if (url.isNull()) { return; } if (dialog.isOpenInBrowser()) { @@ -149,17 +143,32 @@ public class GithubCreateGistAction extends DumbAwareAction { }.queue(); } - @NotNull - private static GithubAuthData getValidAuthData(@NotNull final Project project) throws IOException { - return GithubUtil.computeValueInModal(project, "Access to GitHub", - new ThrowableConvertor<ProgressIndicator, GithubAuthData, IOException>() { - @NotNull - @Override - public GithubAuthData convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.getValidAuthDataFromConfig(project, indicator); - } - } - ); + @Nullable + private static GithubAuthDataHolder getValidAuthData(@NotNull final Project project, boolean isAnonymous) { + if (isAnonymous) { + return new GithubAuthDataHolder(GithubAuthData.createAnonymous()); + } + else { + try { + return GithubUtil + .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubAuthDataHolder, IOException>() { + @NotNull + @Override + public GithubAuthDataHolder convert(ProgressIndicator indicator) throws IOException { + return GithubUtil.getValidAuthDataHolderFromConfig(project, indicator); + } + } + ); + } + catch (GithubOperationCanceledException e) { + return null; + } + catch (IOException e) { + GithubNotifications.showError(project, "Can't create gist", e); + return null; + } + + } } @NotNull @@ -197,10 +206,11 @@ public class GithubCreateGistAction extends DumbAwareAction { @Nullable static String createGist(@NotNull Project project, - @NotNull GithubAuthData auth, + @NotNull GithubAuthDataHolder auth, + @NotNull ProgressIndicator indicator, @NotNull List<FileContent> contents, - boolean isPrivate, - @NotNull String description, + final boolean isPrivate, + @NotNull final String description, @Nullable String filename) { if (contents.isEmpty()) { GithubNotifications.showWarning(project, FAILED_TO_CREATE_GIST, "Can't create empty gist"); @@ -211,8 +221,14 @@ public class GithubCreateGistAction extends DumbAwareAction { contents = Collections.singletonList(new FileContent(filename, entry.getContent())); } try { - GithubGist gist = GithubApiUtil.createGist(auth, contents, description, isPrivate); - return gist.getHtmlUrl(); + final List<FileContent> finalContents = contents; + return GithubUtil.runTask(project, auth, indicator, new ThrowableConvertor<GithubAuthData, GithubGist, IOException>() { + @NotNull + @Override + public GithubGist convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.createGist(auth, finalContents, description, isPrivate); + } + }).getHtmlUrl(); } catch (IOException e) { GithubNotifications.showError(project, FAILED_TO_CREATE_GIST, e); diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index ee357b145601..d06851c89b97 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -8,6 +8,7 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; @@ -37,17 +38,13 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.api.*; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.ui.GithubSelectForkDialog; -import org.jetbrains.plugins.github.util.GithubAuthData; -import org.jetbrains.plugins.github.util.GithubNotifications; -import org.jetbrains.plugins.github.util.GithubUrlUtil; -import org.jetbrains.plugins.github.util.GithubUtil; +import org.jetbrains.plugins.github.util.*; import java.io.IOException; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; -import java.util.concurrent.atomic.AtomicReference; /** * @author Aleksey Pivovarov @@ -63,7 +60,7 @@ public class GithubCreatePullRequestWorker { @NotNull private final String myRemoteName; @NotNull private final String myRemoteUrl; @NotNull private final String myCurrentBranch; - @NotNull private final GithubAuthData myAuth; + @NotNull private final GithubAuthDataHolder myAuthHolder; @NotNull private final Map<String, FutureTask<DiffInfo>> myDiffInfos; @@ -77,7 +74,7 @@ public class GithubCreatePullRequestWorker { @NotNull String remoteName, @NotNull String remoteUrl, @NotNull String currentBranch, - @NotNull GithubAuthData auth) { + @NotNull GithubAuthDataHolder authHolder) { myProject = project; myGit = git; myGitRepository = gitRepository; @@ -85,7 +82,7 @@ public class GithubCreatePullRequestWorker { myRemoteName = remoteName; myRemoteUrl = remoteUrl; myCurrentBranch = currentBranch; - myAuth = auth; + myAuthHolder = authHolder; myDiffInfos = new HashMap<String, FutureTask<DiffInfo>>(); } @@ -134,14 +131,14 @@ public class GithubCreatePullRequestWorker { return null; } - GithubAuthData auth; + GithubAuthDataHolder authHolder; try { - auth = GithubUtil - .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubAuthData, IOException>() { + authHolder = GithubUtil + .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubAuthDataHolder, IOException>() { @NotNull @Override - public GithubAuthData convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.getValidAuthDataFromConfig(project, indicator); + public GithubAuthDataHolder convert(ProgressIndicator indicator) throws IOException { + return GithubUtil.getValidAuthDataHolderFromConfig(project, indicator); } }); } @@ -153,7 +150,7 @@ public class GithubCreatePullRequestWorker { return null; } - return new GithubCreatePullRequestWorker(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName(), auth); + return new GithubCreatePullRequestWorker(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName(), authHolder); } @Nullable @@ -168,7 +165,7 @@ public class GithubCreatePullRequestWorker { GitRemote targetRemote = GithubUtil.findGithubRemote(myGitRepository, forkPath); String targetRemoteName = targetRemote == null ? null : targetRemote.getName(); if (targetRemoteName == null) { - final AtomicReference<Integer> responseRef = new AtomicReference<Integer>(); + final Ref<Integer> responseRef = new Ref<Integer>(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { @@ -182,13 +179,21 @@ public class GithubCreatePullRequestWorker { } // load available branches - List<String> branches = ContainerUtil.map(GithubApiUtil.getRepoBranches(myAuth, forkPath.getUser(), forkPath.getRepository()), - new Function<GithubBranch, String>() { - @Override - public String fun(GithubBranch githubBranch) { - return githubBranch.getName(); - } - }); + List<String> branches = ContainerUtil.map(GithubUtil.runTask(myProject, myAuthHolder, indicator, + new ThrowableConvertor<GithubAuthData, List<GithubBranch>, IOException>() { + @Override + public List<GithubBranch> convert(@NotNull GithubAuthData auth) + throws IOException { + return GithubApiUtil.getRepoBranches(auth, forkPath.getUser(), + forkPath.getRepository()); + } + } + ), new Function<GithubBranch, String>() { + @Override + public String fun(GithubBranch githubBranch) { + return githubBranch.getName(); + } + }); // fetch if (targetRemoteName != null) { @@ -251,7 +256,7 @@ public class GithubCreatePullRequestWorker { @Nullable public GithubFullPath showTargetDialog(boolean firstTime) { - final GithubInfo2 info = getAvailableForksInModal(myProject, myGitRepository, myAuth, myPath); + final GithubInfo2 info = getAvailableForksInModal(myProject, myGitRepository, myAuthHolder, myPath); if (info == null) { return null; } @@ -281,8 +286,8 @@ public class GithubCreatePullRequestWorker { return GithubUtil.computeValueInModal(myProject, "Access to GitHub", new Convertor<ProgressIndicator, GithubFullPath>() { @Nullable @Override - public GithubFullPath convert(ProgressIndicator o) { - return findRepositoryByUser(myProject, user, info.getForks(), myAuth, info.getSource()); + public GithubFullPath convert(ProgressIndicator indicator) { + return findRepositoryByUser(myProject, myAuthHolder, indicator, user, info.getForks(), info.getSource()); } }); } @@ -301,8 +306,11 @@ public class GithubCreatePullRequestWorker { return true; } if (info.getInfo().getBranchToHeadCommits(myGitRepository).isEmpty()) { - GithubNotifications.showWarningDialog(myProject, CANNOT_CREATE_PULL_REQUEST, - "Can't create empty pull request: the branch" + getCurrentBranch() + " in fully merged to the branch " + targetBranch + "."); + GithubNotifications.showWarningDialog(myProject, CANNOT_CREATE_PULL_REQUEST, "Can't create empty pull request: the branch" + + getCurrentBranch() + + " in fully merged to the branch " + + targetBranch + + "."); return false; } if (info.getInfo().getHeadToBranchCommits(myGitRepository).isEmpty()) { @@ -332,7 +340,8 @@ public class GithubCreatePullRequestWorker { LOG.info("Creating pull request"); indicator.setText("Creating pull request..."); - GithubPullRequest request = createPullRequest(project, myAuth, myForkPath, title, description, headBranch, targetBranch); + GithubPullRequest request = + createPullRequest(project, myAuthHolder, indicator, myForkPath, title, description, headBranch, targetBranch); if (request == null) { return; } @@ -357,14 +366,21 @@ public class GithubCreatePullRequestWorker { @Nullable private static GithubPullRequest createPullRequest(@NotNull Project project, - @NotNull GithubAuthData auth, - @NotNull GithubFullPath targetRepo, - @NotNull String title, - @NotNull String description, - @NotNull String head, - @NotNull String base) { + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull final GithubFullPath targetRepo, + @NotNull final String title, + @NotNull final String description, + @NotNull final String head, + @NotNull final String base) { try { - return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, head, base); + return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubPullRequest, IOException>() { + @NotNull + @Override + public GithubPullRequest convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, head, base); + } + }); } catch (IOException e) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e); @@ -451,7 +467,7 @@ public class GithubCreatePullRequestWorker { @Nullable private static GithubInfo2 getAvailableForksInModal(@NotNull final Project project, @NotNull final GitRepository gitRepository, - @NotNull final GithubAuthData auth, + @NotNull final GithubAuthDataHolder authHolder, @NotNull final GithubFullPath path) { try { return GithubUtil @@ -462,7 +478,15 @@ public class GithubCreatePullRequestWorker { final Set<GithubFullPath> forks = new HashSet<GithubFullPath>(); // GitHub - GithubRepoDetailed repo = GithubApiUtil.getDetailedRepoInfo(auth, path.getUser(), path.getRepository()); + GithubRepoDetailed repo = + GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubRepoDetailed, IOException>() { + @NotNull + @Override + public GithubRepoDetailed convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.getDetailedRepoInfo(auth, path.getUser(), path.getRepository()); + } + }); + forks.add(path); if (repo.getParent() != null) { forks.add(repo.getParent().getFullPath()); @@ -507,10 +531,11 @@ public class GithubCreatePullRequestWorker { @Nullable private static GithubFullPath findRepositoryByUser(@NotNull Project project, - @NotNull String user, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull final String user, @NotNull Set<GithubFullPath> forks, - @NotNull GithubAuthData auth, - @NotNull GithubRepo source) { + @NotNull final GithubRepo source) { for (GithubFullPath path : forks) { if (StringUtil.equalsIgnoreCase(user, path.getUser())) { return path; @@ -518,20 +543,28 @@ public class GithubCreatePullRequestWorker { } try { - GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(auth, user, source.getName()); - if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), source.getUserName())) { - return target.getFullPath(); - } - } - catch (IOException ignore) { - // such repo may not exist - } + return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubFullPath, IOException>() { + @Nullable + @Override + public GithubFullPath convert(@NotNull GithubAuthData auth) throws IOException { + try { + GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(auth, user, source.getName()); + if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), source.getUserName())) { + return target.getFullPath(); + } + } + catch (IOException ignore) { + // such repo may not exist + } - try { - GithubRepo fork = GithubApiUtil.findForkByUser(auth, source.getUserName(), source.getName(), user); - if (fork != null) { - return fork.getFullPath(); - } + GithubRepo fork = GithubApiUtil.findForkByUser(auth, source.getUserName(), source.getName(), user); + if (fork != null) { + return fork.getFullPath(); + } + + return null; + } + }); } catch (IOException e) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e); diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java index d3f912545ee2..4faaf7bf568f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java @@ -105,7 +105,6 @@ public class GithubRebaseAction extends DumbAwareAction { GithubNotifications.showError(project, CANNOT_PERFORM_GITHUB_REBASE, "Can't find git repository"); return; } - BasicAction.saveAll(); new Task.Backgroundable(project, "Rebasing GitHub fork...") { @@ -175,15 +174,16 @@ public class GithubRebaseAction extends DumbAwareAction { if (GithubUtil.addGithubRemote(project, gitRepository, "upstream", parentRepoUrl)) { return parentRepoUrl; - } else { + } + else { return null; } } @Nullable private static GithubRepoDetailed loadRepositoryInfo(@NotNull Project project, - @NotNull GitRepository gitRepository, - @NotNull ProgressIndicator indicator) { + @NotNull GitRepository gitRepository, + @NotNull ProgressIndicator indicator) { final String remoteUrl = GithubUtil.findGithubRemoteUrl(gitRepository); if (remoteUrl == null) { GithubNotifications.showError(project, CANNOT_PERFORM_GITHUB_REBASE, "Can't find github remote"); @@ -196,13 +196,14 @@ public class GithubRebaseAction extends DumbAwareAction { } try { - return GithubUtil.runWithValidAuth(project, indicator, new ThrowableConvertor<GithubAuthData, GithubRepoDetailed, IOException>() { - @Override - @NotNull - public GithubRepoDetailed convert(GithubAuthData authData) throws IOException { - return GithubApiUtil.getDetailedRepoInfo(authData, userAndRepo.getUser(), userAndRepo.getRepository()); - } - }); + return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(), indicator, + new ThrowableConvertor<GithubAuthData, GithubRepoDetailed, IOException>() { + @NotNull + @Override + public GithubRepoDetailed convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.getDetailedRepoInfo(auth, userAndRepo.getUser(), userAndRepo.getRepository()); + } + }); } catch (GithubOperationCanceledException e) { return null; @@ -236,7 +237,8 @@ public class GithubRebaseAction extends DumbAwareAction { public void run() { doRebaseCurrentBranch(project, gitRepository.getRoot(), indicator); } - }); + } + ); process.execute(); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java index d3e72a278c0c..99c5ff9020c6 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java @@ -26,13 +26,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog; import com.intellij.openapi.vcs.ui.CommitMessage; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ThrowableConsumer; import com.intellij.util.ThrowableConvertor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; @@ -51,18 +51,18 @@ import git4idea.util.GitUIUtil; import icons.GithubIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.github.api.*; +import org.jetbrains.plugins.github.api.GithubApiUtil; +import org.jetbrains.plugins.github.api.GithubRepo; +import org.jetbrains.plugins.github.api.GithubUserDetailed; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.ui.GithubShareDialog; -import org.jetbrains.plugins.github.util.GithubAuthData; -import org.jetbrains.plugins.github.util.GithubNotifications; -import org.jetbrains.plugins.github.util.GithubUrlUtil; -import org.jetbrains.plugins.github.util.GithubUtil; +import org.jetbrains.plugins.github.util.*; import javax.swing.*; import java.io.IOException; -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled; @@ -125,8 +125,10 @@ public class GithubShareAction extends DumbAwareAction { externalRemoteDetected = !gitRepository.getRemotes().isEmpty(); } + final GithubAuthDataHolder authHolder = GithubAuthDataHolder.createFromSettings(); + // get available GitHub repos with modal progress - final GithubInfo githubInfo = loadGithubInfoWithModal(project); + final GithubInfo githubInfo = loadGithubInfoWithModal(authHolder, project); if (githubInfo == null) { return; } @@ -150,7 +152,7 @@ public class GithubShareAction extends DumbAwareAction { // create GitHub repo (network) LOG.info("Creating GitHub repository"); indicator.setText("Creating GitHub repository..."); - final String url = createGithubRepository(project, githubInfo.getAuthData(), name, description, isPrivate); + final String url = createGithubRepository(project, authHolder, indicator, name, description, isPrivate); if (url == null) { return; } @@ -202,29 +204,28 @@ public class GithubShareAction extends DumbAwareAction { } @Nullable - private static GithubInfo loadGithubInfoWithModal(@NotNull final Project project) { + private static GithubInfo loadGithubInfoWithModal(@NotNull final GithubAuthDataHolder authHolder, @NotNull final Project project) { try { return GithubUtil .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubInfo, IOException>() { + @NotNull @Override public GithubInfo convert(ProgressIndicator indicator) throws IOException { // get existing github repos (network) and validate auth data - final AtomicReference<List<GithubRepo>> availableReposRef = new AtomicReference<List<GithubRepo>>(); - final GithubAuthData auth = - GithubUtil.runAndGetValidAuth(project, indicator, new ThrowableConsumer<GithubAuthData, IOException>() { - @Override - public void consume(GithubAuthData authData) throws IOException { - availableReposRef.set(GithubApiUtil.getUserRepos(authData)); + return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubInfo, IOException>() { + @NotNull + @Override + public GithubInfo convert(@NotNull GithubAuthData auth) throws IOException { + // check access to private repos (network) + GithubUserDetailed userInfo = GithubApiUtil.getCurrentUserDetailed(auth); + + HashSet<String> names = new HashSet<String>(); + for (GithubRepo info : GithubApiUtil.getUserRepos(auth)) { + names.add(info.getName()); } - }); - final HashSet<String> names = new HashSet<String>(); - for (GithubRepo info : availableReposRef.get()) { - names.add(info.getName()); - } - - // check access to private repos (network) - final GithubUserDetailed userInfo = GithubApiUtil.getCurrentUserDetailed(auth); - return new GithubInfo(auth, userInfo, names); + return new GithubInfo(userInfo, names); + } + }); } }); } @@ -239,14 +240,20 @@ public class GithubShareAction extends DumbAwareAction { @Nullable private static String createGithubRepository(@NotNull Project project, - @NotNull GithubAuthData auth, - @NotNull String name, - @NotNull String description, - boolean isPrivate) { + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull final String name, + @NotNull final String description, + final boolean isPrivate) { try { - GithubRepo response = GithubApiUtil.createRepo(auth, name, description, isPrivate); - return response.getHtmlUrl(); + return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubRepo, IOException>() { + @NotNull + @Override + public GithubRepo convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.createRepo(auth, name, description, isPrivate); + } + }).getHtmlUrl(); } catch (IOException e) { GithubNotifications.showError(project, "Failed to create GitHub Repository", e); @@ -286,15 +293,15 @@ public class GithubShareAction extends DumbAwareAction { // ask for files to add final List<VirtualFile> trackedFiles = ChangeListManager.getInstance(project).getAffectedFiles(); - final Collection<VirtualFile> untrackedFiles = filterOutIgnored(project, - repository.getUntrackedFilesHolder().retrieveUntrackedFiles()); + final Collection<VirtualFile> untrackedFiles = + filterOutIgnored(project, repository.getUntrackedFilesHolder().retrieveUntrackedFiles()); trackedFiles.removeAll(untrackedFiles); // fix IDEA-119855 final List<VirtualFile> allFiles = new ArrayList<VirtualFile>(); allFiles.addAll(trackedFiles); allFiles.addAll(untrackedFiles); - final AtomicReference<GithubUntrackedFilesDialog> dialogRef = new AtomicReference<GithubUntrackedFilesDialog>(); + final Ref<GithubUntrackedFilesDialog> dialogRef = new Ref<GithubUntrackedFilesDialog>(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { @@ -429,12 +436,10 @@ public class GithubShareAction extends DumbAwareAction { private static class GithubInfo { @NotNull private final GithubUserDetailed myUser; - @NotNull private final GithubAuthData myAuthData; @NotNull private final HashSet<String> myRepositoryNames; - GithubInfo(@NotNull GithubAuthData auth, @NotNull GithubUserDetailed user, @NotNull HashSet<String> repositoryNames) { + GithubInfo(@NotNull GithubUserDetailed user, @NotNull HashSet<String> repositoryNames) { myUser = user; - myAuthData = auth; myRepositoryNames = repositoryNames; } @@ -444,11 +449,6 @@ public class GithubShareAction extends DumbAwareAction { } @NotNull - public GithubAuthData getAuthData() { - return myAuthData; - } - - @NotNull public HashSet<String> getRepositoryNames() { return myRepositoryNames; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java index ec7d3ae2b51d..581dc16bf25b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java @@ -169,6 +169,10 @@ public class GithubApiUtil { if (tokenAuth != null) { method.addRequestHeader("Authorization", "token " + tokenAuth.getToken()); } + GithubAuthData.BasicAuth basicAuth = auth.getBasicAuth(); + if (basicAuth != null && basicAuth.getCode() != null) { + method.addRequestHeader("X-GitHub-OTP", basicAuth.getCode()); + } for (Header header : headers) { method.addRequestHeader(header); } @@ -401,6 +405,14 @@ public class GithubApiUtil { * Github API */ + public static void askForTwoFactorCodeSMS(@NotNull GithubAuthData auth) { + try { + postRequest(auth, "/authorizations", null, ACCEPT_V3_JSON); + } catch (IOException e) { + LOG.info(e); + } + } + @NotNull public static Collection<String> getTokenScopes(@NotNull GithubAuthData auth) throws IOException { HttpMethod method = null; @@ -448,10 +460,9 @@ public class GithubApiUtil { @NotNull public static String getMasterToken(@NotNull GithubAuthData auth, @Nullable String note) throws IOException { - List<String> scopes = new ArrayList<String>(); - - scopes.add("repo"); // read/write access to public/private repositories - scopes.add("gist"); // create/delete gists + // "repo" - read/write access to public/private repositories + // "gist" - create/delete gists + List<String> scopes = Arrays.asList("repo", "gist"); return getScopedToken(auth, scopes, note); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java index 668913836dbd..ee117b0bdef9 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java @@ -32,6 +32,7 @@ import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.api.GithubRepo; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import org.jetbrains.plugins.github.util.GithubNotifications; import org.jetbrains.plugins.github.util.GithubUtil; @@ -60,12 +61,15 @@ public class GithubCheckoutProvider implements CheckoutProvider { @NotNull @Override public List<GithubRepo> convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.runWithValidAuth(project, indicator, new ThrowableConvertor<GithubAuthData, List<GithubRepo>, IOException>() { - @Override - public List<GithubRepo> convert(GithubAuthData authData) throws IOException { - return GithubApiUtil.getAvailableRepos(authData); - } - }); + return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(), indicator, + new ThrowableConvertor<GithubAuthData, List<GithubRepo>, IOException>() { + @NotNull + @Override + public List<GithubRepo> convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.getAvailableRepos(auth); + } + } + ); } }); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java index 568a010eaeb6..a340de0f62f1 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java @@ -37,6 +37,9 @@ public class GithubHttpAuthDataProvider implements GitHttpAuthDataProvider { } GithubSettings settings = GithubSettings.getInstance(); + if (!settings.isValidGitAuth()) { + return null; + } String host1 = GithubUrlUtil.getHostFromUrl(settings.getHost()); String host2 = GithubUrlUtil.getHostFromUrl(url); diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java index 8af4136507f5..059be25cb7e3 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java +++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java @@ -13,11 +13,12 @@ import com.intellij.util.ui.FormBuilder; import com.intellij.util.ui.GridBag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import org.jetbrains.plugins.github.util.GithubNotifications; import org.jetbrains.plugins.github.util.GithubUtil; -import org.jetbrains.plugins.github.api.GithubApiUtil; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -124,15 +125,19 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor @Override public String convert(ProgressIndicator indicator) throws IOException { return GithubUtil - .runWithValidBasicAuthForHost(myProject, indicator, getHost(), new ThrowableConvertor<GithubAuthData, String, IOException>() { - @NotNull - @Override - public String convert(GithubAuthData auth) throws IOException { - return GithubApiUtil.getReadOnlyToken(auth, getRepoAuthor(), getRepoName(), "Intellij tasks plugin"); - } - }); + .runTaskWithBasicAuthForHost(myProject, GithubAuthDataHolder.createFromSettings(), indicator, getHost(), + new ThrowableConvertor<GithubAuthData, String, IOException>() { + @NotNull + @Override + public String convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil + .getReadOnlyToken(auth, getRepoAuthor(), getRepoName(), "Intellij tasks plugin"); + } + } + ); } - })); + }) + ); } catch (GithubOperationCanceledException ignore) { } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java index fac45c597980..80acc787d6c6 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java @@ -16,25 +16,17 @@ package org.jetbrains.plugins.github.ui; import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.github.util.GithubAuthData; -import org.jetbrains.plugins.github.util.GithubSettings; /** * @author Aleksey Pivovarov */ public class GithubBasicLoginDialog extends GithubLoginDialog { - public GithubBasicLoginDialog(@Nullable Project project) { - super(project); + public GithubBasicLoginDialog(@NotNull Project project, @NotNull GithubAuthData oldAuthData, @NotNull String host) { + super(project, oldAuthData); myGithubLoginPanel.lockAuthType(GithubAuthData.AuthType.BASIC); - } - - @Override - protected void saveCredentials(GithubAuthData auth) { - final GithubSettings settings = GithubSettings.getInstance(); - if (settings.getAuthType() != GithubAuthData.AuthType.TOKEN) { - settings.setCredentials(myGithubLoginPanel.getHost(), auth, myGithubLoginPanel.isSavePasswordSelected()); - } + myGithubLoginPanel.lockHost(host); } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java index 7660fb569b7f..c4e33f6e136c 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java @@ -6,9 +6,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.util.ThrowableConvertor; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.api.GithubUser; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import org.jetbrains.plugins.github.util.GithubSettings; import org.jetbrains.plugins.github.util.GithubUtil; @@ -25,18 +25,25 @@ public class GithubLoginDialog extends DialogWrapper { protected final GithubLoginPanel myGithubLoginPanel; protected final GithubSettings mySettings; + protected final Project myProject; - public GithubLoginDialog(@Nullable final Project project) { + protected GithubAuthData myAuthData; + + public GithubLoginDialog(@NotNull final Project project, @NotNull GithubAuthData oldAuthData) { super(project, true); myProject = project; + myGithubLoginPanel = new GithubLoginPanel(this); - mySettings = GithubSettings.getInstance(); - myGithubLoginPanel.setHost(mySettings.getHost()); - myGithubLoginPanel.setLogin(mySettings.getLogin()); - myGithubLoginPanel.setAuthType(mySettings.getAuthType()); + myGithubLoginPanel.setHost(oldAuthData.getHost()); + myGithubLoginPanel.setAuthType(oldAuthData.getAuthType()); + GithubAuthData.BasicAuth basicAuth = oldAuthData.getBasicAuth(); + if (basicAuth != null) { + myGithubLoginPanel.setLogin(basicAuth.getLogin()); + } + mySettings = GithubSettings.getInstance(); if (mySettings.isSavePasswordMakesSense()) { myGithubLoginPanel.setSavePasswordSelected(mySettings.isSavePassword()); } @@ -71,17 +78,18 @@ public class GithubLoginDialog extends DialogWrapper { @Override protected void doOKAction() { - final GithubAuthData auth = myGithubLoginPanel.getAuthData(); + final GithubAuthDataHolder authHolder = new GithubAuthDataHolder(myGithubLoginPanel.getAuthData()); try { GithubUtil.computeValueInModal(myProject, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubUser, IOException>() { @NotNull @Override public GithubUser convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.checkAuthData(auth); + return GithubUtil.checkAuthData(myProject, authHolder, indicator); } }); - saveCredentials(auth); + myAuthData = authHolder.getAuthData(); + if (mySettings.isSavePasswordMakesSense()) { mySettings.setSavePassword(myGithubLoginPanel.isSavePasswordSelected()); } @@ -93,21 +101,19 @@ public class GithubLoginDialog extends DialogWrapper { } } - protected void saveCredentials(GithubAuthData auth) { - final GithubSettings settings = GithubSettings.getInstance(); - settings.setCredentials(myGithubLoginPanel.getHost(), auth, myGithubLoginPanel.isSavePasswordSelected()); - } - - public void clearErrors() { - setErrorText(null); + public boolean isSavePasswordSelected() { + return myGithubLoginPanel.isSavePasswordSelected(); } @NotNull public GithubAuthData getAuthData() { - return myGithubLoginPanel.getAuthData(); + if (myAuthData == null) { + throw new IllegalStateException("AuthData is not set"); + } + return myAuthData; } - public void lockHost(String host) { - myGithubLoginPanel.lockHost(host); + public void clearErrors() { + setErrorText(null); } }
\ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java index 9e8f9ab300ae..80e5a6fb8d8e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java @@ -100,7 +100,7 @@ public class GithubSettingsPanel { @NotNull @Override public GithubUser convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.checkAuthData(auth); + return GithubUtil.checkAuthData(project, new GithubAuthDataHolder(auth), indicator); } }); @@ -132,13 +132,14 @@ public class GithubSettingsPanel { @NotNull @Override public String convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.runWithValidBasicAuthForHost(project, indicator, getHost(), - new ThrowableConvertor<GithubAuthData, String, IOException>() { - @Override - public String convert(GithubAuthData auth) throws IOException { - return GithubApiUtil.getMasterToken(auth, "IntelliJ plugin"); - } - } + return GithubUtil.runTaskWithBasicAuthForHost(project, GithubAuthDataHolder.createFromSettings(), indicator, getHost(), + new ThrowableConvertor<GithubAuthData, String, IOException>() { + @NotNull + @Override + public String convert(@NotNull GithubAuthData auth) throws IOException { + return GithubApiUtil.getMasterToken(auth, "IntelliJ plugin"); + } + } ); } }) @@ -294,7 +295,7 @@ public class GithubSettingsPanel { public void apply() { if (myCredentialsModified) { - mySettings.setCredentials(getHost(), getAuthData(), true); + mySettings.setAuthData(getAuthData(), true); } mySettings.setConnectionTimeout(getConnectionTimeout()); resetCredentialsModification(); diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java index 63e93a6e230e..f11044422154 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.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. @@ -21,10 +21,12 @@ import org.jetbrains.plugins.github.api.GithubApiUtil; /** * Container for authentication data: - * - host - * - login + * * host + * * credentials * - login/password pair - * or + * or + * - login/password pair/2 factor code + * or * - OAuth2 access token * * @author Aleksey Pivovarov @@ -38,7 +40,6 @@ public class GithubAuthData { @Nullable private final TokenAuth myTokenAuth; private final boolean myUseProxy; - private GithubAuthData(@NotNull AuthType authType, @NotNull String host, @Nullable BasicAuth basicAuth, @@ -51,6 +52,10 @@ public class GithubAuthData { myUseProxy = useProxy; } + public static GithubAuthData createFromSettings() { + return GithubSettings.getInstance().getAuthData(); + } + public static GithubAuthData createAnonymous() { return createAnonymous(GithubApiUtil.DEFAULT_GITHUB_HOST); } @@ -63,6 +68,13 @@ public class GithubAuthData { return new GithubAuthData(AuthType.BASIC, host, new BasicAuth(login, password), null, true); } + public static GithubAuthData createBasicAuthTF(@NotNull String host, + @NotNull String login, + @NotNull String password, + @NotNull String code) { + return new GithubAuthData(AuthType.BASIC, host, new BasicAuth(login, password, code), null, true); + } + public static GithubAuthData createTokenAuth(@NotNull String host, @NotNull String token) { return new GithubAuthData(AuthType.TOKEN, host, null, new TokenAuth(token), true); } @@ -95,13 +107,28 @@ public class GithubAuthData { return myUseProxy; } + @NotNull + public GithubAuthData copyWithTwoFactorCode(@NotNull String code) { + if (myBasicAuth == null) { + throw new IllegalStateException("Two factor authentication can be used only with Login/Password"); + } + + return createBasicAuthTF(getHost(), myBasicAuth.getLogin(), myBasicAuth.getPassword(), code); + } + public static class BasicAuth { @NotNull private final String myLogin; @NotNull private final String myPassword; + @Nullable private final String myCode; private BasicAuth(@NotNull String login, @NotNull String password) { + this(login, password, null); + } + + private BasicAuth(@NotNull String login, @NotNull String password, @Nullable String code) { myLogin = login; myPassword = password; + myCode = code; } @NotNull @@ -113,6 +140,11 @@ public class GithubAuthData { public String getPassword() { return myPassword; } + + @Nullable + public String getCode() { + return myCode; + } } public static class TokenAuth { diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java new file mode 100644 index 000000000000..695dfe734c34 --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.github.util; + +import com.intellij.openapi.util.ThrowableComputable; +import org.jetbrains.annotations.NotNull; + + +public class GithubAuthDataHolder { + @NotNull private GithubAuthData myAuthData; + + public GithubAuthDataHolder(@NotNull GithubAuthData auth) { + myAuthData = auth; + } + + @NotNull + public synchronized GithubAuthData getAuthData() { + return myAuthData; + } + + public synchronized <T extends Throwable> void runTransaction(@NotNull GithubAuthData expected, + @NotNull ThrowableComputable<GithubAuthData, T> task) throws T { + if (expected != myAuthData) { + return; + } + + myAuthData = task.compute(); + } + + public static GithubAuthDataHolder createFromSettings() { + return new GithubAuthDataHolder(GithubSettings.getInstance().getAuthData()); + } +} diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java index 49199c0d156b..3523e412a95e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java @@ -59,6 +59,7 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S public boolean PRIVATE_GIST = true; public boolean SAVE_PASSWORD = true; public int CONNECTION_TIMEOUT = 5000; + public boolean VALID_GIT_AUTH = true; } public static GithubSettings getInstance() { @@ -120,6 +121,10 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S return myState.SAVE_PASSWORD; } + public boolean isValidGitAuth() { + return myState.VALID_GIT_AUTH; + } + public boolean isSavePasswordMakesSense() { final PasswordSafeImpl passwordSafe = (PasswordSafeImpl)PasswordSafe.getInstance(); return passwordSafe.getSettings().getProviderType() == PasswordSafeSettings.ProviderType.MASTER_PASSWORD; @@ -137,6 +142,10 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S myState.SAVE_PASSWORD = savePassword; } + public void setValidGitAuth(final boolean validGitAuth) { + myState.VALID_GIT_AUTH = validGitAuth; + } + public void setOpenInBrowserGist(final boolean openInBrowserGist) { myState.OPEN_IN_BROWSER_GIST = openInBrowserGist; } @@ -172,10 +181,25 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S } } + private static boolean isValidGitAuth(@NotNull GithubAuthData auth) { + switch (auth.getAuthType()) { + case BASIC: + assert auth.getBasicAuth() != null; + return auth.getBasicAuth().getCode() == null; + case TOKEN: + return true; + case ANONYMOUS: + return false; + default: + throw new IllegalStateException("GithubSettings: setAuthData - wrong AuthType: " + auth.getAuthType()); + } + } + @NotNull public GithubAuthData getAuthData() { switch (getAuthType()) { case BASIC: + //noinspection ConstantConditions return GithubAuthData.createBasicAuth(getHost(), getLogin(), getPassword()); case TOKEN: return GithubAuthData.createTokenAuth(getHost(), getPassword()); @@ -186,8 +210,11 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S } } - private void setAuthData(@NotNull GithubAuthData auth, boolean rememberPassword) { + public void setAuthData(@NotNull GithubAuthData auth, boolean rememberPassword) { + setValidGitAuth(isValidGitAuth(auth)); + setAuthType(auth.getAuthType()); + setHost(auth.getHost()); switch (auth.getAuthType()) { case BASIC: @@ -205,12 +232,7 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S setPassword("", rememberPassword); break; default: - throw new IllegalStateException("GithubSettings: setAuthData - wrong AuthType: " + getAuthType()); + throw new IllegalStateException("GithubSettings: setAuthData - wrong AuthType: " + auth.getAuthType()); } } - - public void setCredentials(@NotNull String host, @NotNull GithubAuthData auth, boolean rememberPassword) { - setHost(host); - setAuthData(auth, rememberPassword); - } }
\ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubUrlUtil.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubUrlUtil.java index a79a2f4147e1..d65b5d7315fc 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubUrlUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubUrlUtil.java @@ -126,6 +126,7 @@ public class GithubUrlUtil { } public static boolean isGithubUrl(@NotNull String url, @NotNull String host) { + host = getHostFromUrl(host); url = removeProtocolPrefix(url); if (StringUtil.startsWithIgnoreCase(url, host)) { if (url.length() > host.length() && ":/".indexOf(url.charAt(host.length())) == -1) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java index a3eb6c4ca1d7..db137884f764 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java @@ -22,7 +22,10 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; @@ -46,13 +49,13 @@ import org.jetbrains.plugins.github.api.GithubFullPath; import org.jetbrains.plugins.github.api.GithubUserDetailed; import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; +import org.jetbrains.plugins.github.exceptions.GithubTwoFactorAuthenticationException; import org.jetbrains.plugins.github.ui.GithubBasicLoginDialog; import org.jetbrains.plugins.github.ui.GithubLoginDialog; import java.io.IOException; import java.net.UnknownHostException; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; /** * Various utility methods for the GutHub plugin. @@ -65,119 +68,194 @@ public class GithubUtil { public static final Logger LOG = Logger.getInstance("github"); - // TODO: these functions ugly inside and out + // TODO: Consider sharing of GithubAuthData between actions (as member of GithubSettings) @NotNull - public static GithubAuthData runAndGetValidAuth(@Nullable Project project, - @NotNull ProgressIndicator indicator, - @NotNull ThrowableConsumer<GithubAuthData, IOException> task) throws IOException { - GithubAuthData auth = GithubSettings.getInstance().getAuthData(); + public static <T> T runTask(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull ThrowableConvertor<GithubAuthData, T, IOException> task) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); try { - if (auth.getAuthType() == GithubAuthData.AuthType.ANONYMOUS) { - throw new GithubAuthenticationException("Bad authentication type"); - } - task.consume(auth); - return auth; + return task.convert(auth); + } + catch (GithubTwoFactorAuthenticationException e) { + getTwoFactorAuthData(project, authHolder, indicator, auth); + return runTask(project, authHolder, indicator, task); } catch (GithubAuthenticationException e) { - auth = getValidAuthData(project, indicator); - task.consume(auth); - return auth; + getValidAuthData(project, authHolder, indicator, auth); + return runTask(project, authHolder, indicator, task); } } - @NotNull - public static <T> T runWithValidAuth(@Nullable Project project, - @NotNull ProgressIndicator indicator, - @NotNull ThrowableConvertor<GithubAuthData, T, IOException> task) throws IOException { - GithubAuthData auth = GithubSettings.getInstance().getAuthData(); + public static void runTask(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull ThrowableConsumer<GithubAuthData, IOException> task) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); try { - if (auth.getAuthType() == GithubAuthData.AuthType.ANONYMOUS) { - throw new GithubAuthenticationException("Bad authentication type"); - } - return task.convert(auth); + task.consume(auth); + } + catch (GithubTwoFactorAuthenticationException e) { + getTwoFactorAuthData(project, authHolder, indicator, auth); + runTask(project, authHolder, indicator, task); } catch (GithubAuthenticationException e) { - auth = getValidAuthData(project, indicator); - return task.convert(auth); + getValidAuthData(project, authHolder, indicator, auth); + runTask(project, authHolder, indicator, task); } } @NotNull - public static <T> T runWithValidBasicAuthForHost(@Nullable Project project, - @NotNull ProgressIndicator indicator, - @NotNull String host, - @NotNull ThrowableConvertor<GithubAuthData, T, IOException> task) throws IOException { - GithubSettings settings = GithubSettings.getInstance(); - GithubAuthData auth = null; + public static <T> T runTaskWithBasicAuthForHost(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator, + @NotNull String host, + @NotNull ThrowableConvertor<GithubAuthData, T, IOException> task) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); try { - if (settings.getAuthType() != GithubAuthData.AuthType.BASIC || - !StringUtil.equalsIgnoreCase(GithubUrlUtil.getApiUrl(host), GithubUrlUtil.getApiUrl(settings.getHost()))) { - throw new GithubAuthenticationException("Bad authentication type"); + if (auth.getAuthType() != GithubAuthData.AuthType.BASIC) { + throw new GithubAuthenticationException("Expected basic authentication"); } - auth = settings.getAuthData(); return task.convert(auth); } + catch (GithubTwoFactorAuthenticationException e) { + getTwoFactorAuthData(project, authHolder, indicator, auth); + return runTaskWithBasicAuthForHost(project, authHolder, indicator, host, task); + } catch (GithubAuthenticationException e) { - auth = getValidBasicAuthDataForHost(project, indicator, host); - return task.convert(auth); + getValidBasicAuthDataForHost(project, authHolder, indicator, auth, host); + return runTaskWithBasicAuthForHost(project, authHolder, indicator, host, task); } } - /** - * @return null if user canceled login dialog. Valid GithubAuthData otherwise. - */ @NotNull - public static GithubAuthData getValidAuthData(@Nullable Project project, @NotNull ProgressIndicator indicator) - throws GithubOperationCanceledException { - final GithubLoginDialog dialog = new GithubLoginDialog(project); - ApplicationManager.getApplication().invokeAndWait(new Runnable() { + private static GithubUserDetailed testConnection(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); + try { + return GithubApiUtil.getCurrentUserDetailed(auth); + } + catch (GithubTwoFactorAuthenticationException e) { + getTwoFactorAuthData(project, authHolder, indicator, auth); + return testConnection(project, authHolder, indicator); + } + } + + public static void getValidAuthData(@NotNull final Project project, + @NotNull final GithubAuthDataHolder authHolder, + @NotNull final ProgressIndicator indicator, + @NotNull final GithubAuthData oldAuth) throws GithubOperationCanceledException { + authHolder.runTransaction(oldAuth, new ThrowableComputable<GithubAuthData, GithubOperationCanceledException>() { @Override - public void run() { - DialogManager.show(dialog); + @NotNull + public GithubAuthData compute() throws GithubOperationCanceledException { + final GithubLoginDialog dialog = new GithubLoginDialog(project, oldAuth); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + DialogManager.show(dialog); + } + }, indicator.getModalityState()); + if (!dialog.isOK()) { + throw new GithubOperationCanceledException("Can't get valid credentials"); + } + GithubAuthData authData = dialog.getAuthData(); + + GithubSettings.getInstance().setAuthData(authData, dialog.isSavePasswordSelected()); + return authData; } - }, indicator.getModalityState()); - if (!dialog.isOK()) { - throw new GithubOperationCanceledException("Can't get valid credentials"); - } - return dialog.getAuthData(); + }); } - /** - * @return null if user canceled login dialog. Valid GithubAuthData otherwise. - */ - @NotNull - public static GithubAuthData getValidBasicAuthDataForHost(@Nullable Project project, - @NotNull ProgressIndicator indicator, - @NotNull String host) throws GithubOperationCanceledException { - final GithubLoginDialog dialog = new GithubBasicLoginDialog(project); - dialog.lockHost(host); - ApplicationManager.getApplication().invokeAndWait(new Runnable() { + public static void getValidBasicAuthDataForHost(@NotNull final Project project, + @NotNull final GithubAuthDataHolder authHolder, + @NotNull final ProgressIndicator indicator, + @NotNull final GithubAuthData oldAuth, + @NotNull final String host) throws GithubOperationCanceledException { + authHolder.runTransaction(oldAuth, new ThrowableComputable<GithubAuthData, GithubOperationCanceledException>() { @Override - public void run() { - DialogManager.show(dialog); + @NotNull + public GithubAuthData compute() throws GithubOperationCanceledException { + final GithubLoginDialog dialog = new GithubBasicLoginDialog(project, oldAuth, host); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + DialogManager.show(dialog); + } + }, indicator.getModalityState()); + if (!dialog.isOK()) { + throw new GithubOperationCanceledException("Can't get valid credentials"); + } + GithubAuthData authData = dialog.getAuthData(); + + final GithubSettings settings = GithubSettings.getInstance(); + if (settings.getAuthType() != GithubAuthData.AuthType.TOKEN) { + GithubSettings.getInstance().setAuthData(authData, dialog.isSavePasswordSelected()); + } + return authData; } - }, indicator.getModalityState()); - if (!dialog.isOK()) { - throw new GithubOperationCanceledException("Can't get valid credentials"); - } - return dialog.getAuthData(); + }); + } + + private static void getTwoFactorAuthData(@NotNull final Project project, + @NotNull final GithubAuthDataHolder authHolder, + @NotNull final ProgressIndicator indicator, + @NotNull final GithubAuthData oldAuth) throws GithubOperationCanceledException { + authHolder.runTransaction(oldAuth, new ThrowableComputable<GithubAuthData, GithubOperationCanceledException>() { + @Override + @NotNull + public GithubAuthData compute() throws GithubOperationCanceledException { + if (authHolder.getAuthData().getAuthType() != GithubAuthData.AuthType.BASIC) { + throw new GithubOperationCanceledException("Two factor authentication can be used only with Login/Password"); + } + + GithubApiUtil.askForTwoFactorCodeSMS(oldAuth); + + final Ref<String> codeRef = new Ref<String>(); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + codeRef.set(Messages.showInputDialog(project, "Authentication Code", "Github Two-Factor Authentication", null)); + } + }, indicator.getModalityState()); + if (codeRef.isNull()) { + throw new GithubOperationCanceledException("Can't get two factor authentication code"); + } + + GithubSettings settings = GithubSettings.getInstance(); + if (settings.getAuthType() == GithubAuthData.AuthType.BASIC && + StringUtil.equalsIgnoreCase(settings.getLogin(), oldAuth.getBasicAuth().getLogin())) { + settings.setValidGitAuth(false); + } + + return oldAuth.copyWithTwoFactorCode(codeRef.get()); + } + }); } @NotNull - public static GithubAuthData getValidAuthDataFromConfig(@Nullable Project project, @NotNull ProgressIndicator indicator) + public static GithubAuthDataHolder getValidAuthDataHolderFromConfig(@NotNull Project project, @NotNull ProgressIndicator indicator) throws IOException { - GithubAuthData auth = GithubSettings.getInstance().getAuthData(); + GithubAuthData auth = GithubAuthData.createFromSettings(); + GithubAuthDataHolder authHolder = new GithubAuthDataHolder(auth); try { - checkAuthData(auth); - return auth; + checkAuthData(project, authHolder, indicator); + return authHolder; } catch (GithubAuthenticationException e) { - return getValidAuthData(project, indicator); + getValidAuthData(project, authHolder, indicator, auth); + return authHolder; } } @NotNull - public static GithubUserDetailed checkAuthData(@NotNull GithubAuthData auth) throws IOException { + public static GithubUserDetailed checkAuthData(@NotNull Project project, + @NotNull GithubAuthDataHolder authHolder, + @NotNull ProgressIndicator indicator) throws IOException { + GithubAuthData auth = authHolder.getAuthData(); + if (StringUtil.isEmptyOrSpaces(auth.getHost())) { throw new GithubAuthenticationException("Target host not defined"); } @@ -201,37 +279,31 @@ public class GithubUtil { throw new GithubAuthenticationException("Anonymous connection not allowed"); } - return testConnection(auth); + return testConnection(project, authHolder, indicator); } - @NotNull - private static GithubUserDetailed testConnection(@NotNull GithubAuthData auth) throws IOException { - return GithubApiUtil.getCurrentUserDetailed(auth); - } - - public static <T, E extends Throwable> T computeValueInModal(@NotNull Project project, - @NotNull String caption, - @NotNull final ThrowableConvertor<ProgressIndicator, T, E> task) throws E { - final AtomicReference<T> dataRef = new AtomicReference<T>(); - final AtomicReference<E> exceptionRef = new AtomicReference<E>(); + public static <T> T computeValueInModal(@NotNull Project project, + @NotNull String caption, + @NotNull final ThrowableConvertor<ProgressIndicator, T, IOException> task) throws IOException { + final Ref<T> dataRef = new Ref<T>(); + final Ref<IOException> exceptionRef = new Ref<IOException>(); ProgressManager.getInstance().run(new Task.Modal(project, caption, true) { public void run(@NotNull ProgressIndicator indicator) { try { dataRef.set(task.convert(indicator)); } + catch (IOException e) { + exceptionRef.set(e); + } catch (Error e) { - throw e; + exceptionRef.set(new GithubOperationCanceledException(e)); } catch (RuntimeException e) { - throw e; - } - catch (Throwable e) { - //noinspection unchecked - exceptionRef.set((E)e); + exceptionRef.set(new GithubOperationCanceledException(e)); } } }); - if (exceptionRef.get() != null) { + if (!exceptionRef.isNull()) { throw exceptionRef.get(); } return dataRef.get(); @@ -240,7 +312,7 @@ public class GithubUtil { public static <T> T computeValueInModal(@NotNull Project project, @NotNull String caption, @NotNull final Convertor<ProgressIndicator, T> task) { - final AtomicReference<T> dataRef = new AtomicReference<T>(); + final Ref<T> dataRef = new Ref<T>(); ProgressManager.getInstance().run(new Task.Modal(project, caption, true) { public void run(@NotNull ProgressIndicator indicator) { dataRef.set(task.convert(indicator)); diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTest.java index 0d394d58f09d..f7ae343204f2 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTest.java @@ -15,8 +15,11 @@ */ package org.jetbrains.plugins.github; +import com.intellij.mock.MockProgressIndicator; import com.intellij.notification.NotificationType; +import com.intellij.openapi.progress.ProgressIndicator; import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import java.util.Collections; import java.util.List; @@ -27,10 +30,12 @@ import static org.jetbrains.plugins.github.api.GithubGist.FileContent; * @author Aleksey Pivovarov */ public class GithubCreateGistTest extends GithubCreateGistTestBase { + private final ProgressIndicator myIndicator = new MockProgressIndicator(); + public void testSimple() throws Throwable { List<FileContent> expected = createContent(); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), expected, true, GIST_DESCRIPTION, null); + String url = GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, expected, true, GIST_DESCRIPTION, null); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -44,7 +49,9 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { public void testAnonymous() throws Throwable { List<FileContent> expected = createContent(); - String url = GithubCreateGistAction.createGist(myProject, GithubAuthData.createAnonymous(myHost), expected, true, GIST_DESCRIPTION, null); + String url = GithubCreateGistAction + .createGist(myProject, new GithubAuthDataHolder(GithubAuthData.createAnonymous(myHost)), myIndicator, expected, true, + GIST_DESCRIPTION, null); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -62,7 +69,8 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { public void testUnusedFilenameField() throws Throwable { List<FileContent> expected = createContent(); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), expected, true, GIST_DESCRIPTION, "filename"); + String url = + GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, expected, true, GIST_DESCRIPTION, "filename"); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -77,7 +85,8 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { List<FileContent> content = Collections.singletonList(new FileContent("file.txt", "file.txt content")); List<FileContent> expected = Collections.singletonList(new FileContent("filename", "file.txt content")); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), content, true, GIST_DESCRIPTION, "filename"); + String url = + GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, content, true, GIST_DESCRIPTION, "filename"); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -91,7 +100,7 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { public void testPublic() throws Throwable { List<FileContent> expected = createContent(); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), expected, false, GIST_DESCRIPTION, null); + String url = GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, expected, false, GIST_DESCRIPTION, null); assertNotNull(url); GIST_ID = url.substring(url.lastIndexOf('/') + 1); @@ -105,33 +114,35 @@ public class GithubCreateGistTest extends GithubCreateGistTestBase { public void testEmpty() throws Throwable { List<FileContent> expected = Collections.emptyList(); - String url = GithubCreateGistAction.createGist(myProject, myGitHubSettings.getAuthData(), expected, true, GIST_DESCRIPTION, null); + String url = GithubCreateGistAction.createGist(myProject, getAuthDataHolder(), myIndicator, expected, true, GIST_DESCRIPTION, null); assertNull("Gist was created", url); checkNotification(NotificationType.WARNING, "Can't create Gist", "Can't create empty gist"); } public void testWrongLogin() throws Throwable { - registerDefaultLoginDialogHandler(); + registerCancelingLoginDialogHandler(); List<FileContent> expected = createContent(); GithubAuthData auth = myGitHubSettings.getAuthData(); GithubAuthData myAuth = GithubAuthData.createBasicAuth(auth.getHost(), myLogin1 + "some_suffix", myPassword); - String url = GithubCreateGistAction.createGist(myProject, myAuth, expected, true, GIST_DESCRIPTION, null); + String url = + GithubCreateGistAction.createGist(myProject, new GithubAuthDataHolder(myAuth), myIndicator, expected, true, GIST_DESCRIPTION, null); assertNull("Gist was created", url); checkNotification(NotificationType.ERROR, "Can't create Gist", null); } public void testWrongPassword() throws Throwable { - registerDefaultLoginDialogHandler(); + registerCancelingLoginDialogHandler(); List<FileContent> expected = createContent(); GithubAuthData auth = myGitHubSettings.getAuthData(); GithubAuthData myAuth = GithubAuthData.createBasicAuth(auth.getHost(), myLogin1, myPassword + "some_suffix"); - String url = GithubCreateGistAction.createGist(myProject, myAuth, expected, true, GIST_DESCRIPTION, null); + String url = + GithubCreateGistAction.createGist(myProject, new GithubAuthDataHolder(myAuth), myIndicator, expected, true, GIST_DESCRIPTION, null); assertNull("Gist was created", url); checkNotification(NotificationType.ERROR, "Can't create Gist", null); diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java index 5e785fa7de44..17a0c68781e4 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java @@ -25,6 +25,7 @@ import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.api.GithubGist; import org.jetbrains.plugins.github.test.GithubTest; import org.jetbrains.plugins.github.ui.GithubLoginDialog; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; import java.io.IOException; import java.util.ArrayList; @@ -51,6 +52,11 @@ public abstract class GithubCreateGistTestBase extends GithubTest { deleteGist(); } + @NotNull + protected GithubAuthDataHolder getAuthDataHolder() { + return new GithubAuthDataHolder(myGitHubSettings.getAuthData()); + } + protected void deleteGist() throws IOException { if (GIST_ID != null) { GithubApiUtil.deleteGist(myGitHubSettings.getAuthData(), GIST_ID); @@ -133,7 +139,7 @@ public abstract class GithubCreateGistTestBase extends GithubTest { assertTrue("Gist content differs from sample", Comparing.haveEqualElements(expected, actual)); } - protected void registerDefaultLoginDialogHandler() { + protected void registerCancelingLoginDialogHandler() { myDialogManager.registerDialogHandler(GithubLoginDialog.class, new TestDialogHandler<GithubLoginDialog>() { @Override public int handleDialog(GithubLoginDialog dialog) { diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubUrlUtilTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubUrlUtilTest.java index ce187b76e1ef..636d14d149d1 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubUrlUtilTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubUrlUtilTest.java @@ -90,7 +90,7 @@ public class GithubUrlUtilTest extends UsefulTestCase { }); } - public void testIsGithubUrl() throws Throwable { + public void testIsGithubUrl1() throws Throwable { TestCase<Boolean> tests = new TestCase<Boolean>(); tests.add("http://github.com/user/repo", true); @@ -118,13 +118,50 @@ public class GithubUrlUtilTest extends UsefulTestCase { runTestCase(tests, new Convertor<String, Boolean>() { @Override public Boolean convert(String in) { - return isGithubUrl(in, removeTrailingSlash(removeProtocolPrefix("https://github.com/"))); + return isGithubUrl(in, "https://github.com/"); } }); runTestCase(tests, new Convertor<String, Boolean>() { @Override public Boolean convert(String in) { - return isGithubUrl(in, removeTrailingSlash(removeProtocolPrefix("http://GitHub.com"))); + return isGithubUrl(in, "http://GitHub.com"); + } + }); + } + + public void testIsGithubUrl2() throws Throwable { + TestCase<Boolean> tests = new TestCase<Boolean>(); + + tests.add("http://git.code.example.co.jp/user/repo", true); + tests.add("https://git.code.example.co.jp/user/repo", true); + tests.add("git://git.code.example.co.jp/user/repo", true); + tests.add("git@git.code.example.co.jp:user/repo", true); + + tests.add("http://git.code.example.co/user/repo", false); + tests.add("http://code.example.co.jp/user/repo", false); + + runTestCase(tests, new Convertor<String, Boolean>() { + @Override + public Boolean convert(String in) { + return isGithubUrl(in, "git.code.example.co.jp"); + } + }); + runTestCase(tests, new Convertor<String, Boolean>() { + @Override + public Boolean convert(String in) { + return isGithubUrl(in, "http://git.code.example.co.jp"); + } + }); + runTestCase(tests, new Convertor<String, Boolean>() { + @Override + public Boolean convert(String in) { + return isGithubUrl(in, "https://git.code.example.co.jp/github/server"); + } + }); + runTestCase(tests, new Convertor<String, Boolean>() { + @Override + public Boolean convert(String in) { + return isGithubUrl(in, "git.code.example.co.jp/api"); } }); } diff --git a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java index 2c9496e9a27e..1f7635d35601 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java @@ -210,7 +210,7 @@ public abstract class GithubTest extends UsefulTestCase { myAuth = GithubAuthData.createBasicAuth(host, login1, password); myGitHubSettings = GithubSettings.getInstance(); - myGitHubSettings.setCredentials(myHost, myAuth, false); + myGitHubSettings.setAuthData(myAuth, false); myDialogManager = (TestDialogManager)ServiceManager.getService(DialogManager.class); myNotificator = (TestNotificator)ServiceManager.getService(myProject, Notificator.class); diff --git a/plugins/google-app-engine/jps-plugin/google-app-engine-jps-plugin.iml b/plugins/google-app-engine/jps-plugin/google-app-engine-jps-plugin.iml index e471a6a62370..313b6317ce0a 100644 --- a/plugins/google-app-engine/jps-plugin/google-app-engine-jps-plugin.iml +++ b/plugins/google-app-engine/jps-plugin/google-app-engine-jps-plugin.iml @@ -13,6 +13,7 @@ <orderEntry type="module" module-name="jps-model-serialization" /> <orderEntry type="module" module-name="jps-model-impl" scope="TEST" /> <orderEntry type="module" module-name="appEngine-runtime" /> + <orderEntry type="module" module-name="jps-serialization-tests" scope="TEST" /> </component> </module> diff --git a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java index d8d32974aef4..af83972c7ec5 100644 --- a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java +++ b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java @@ -19,14 +19,18 @@ package org.jetbrains.jps.incremental.groovy; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; +import com.intellij.util.Function; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtilRt; +import com.intellij.util.lang.UrlClassLoader; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.ClassReader; +import org.jetbrains.groovy.compiler.rt.GroovyRtConstants; import org.jetbrains.jps.ModuleChunk; import org.jetbrains.jps.ProjectPaths; import org.jetbrains.jps.builders.BuildRootIndex; @@ -63,6 +67,7 @@ import java.util.concurrent.Future; * Date: 10/25/11 */ public class GroovyBuilder extends ModuleLevelBuilder { + private static final int ourOptimizeThreshold = Integer.parseInt(System.getProperty("groovyc.optimized.class.loading.threshold", "10")); private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.groovy.GroovyBuilder"); private static final Key<Boolean> CHUNK_REBUILD_ORDERED = Key.create("CHUNK_REBUILD_ORDERED"); private static final Key<Map<String, String>> STUB_TO_SRC = Key.create("STUB_TO_SRC"); @@ -86,6 +91,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { ModuleChunk chunk, DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder, OutputConsumer outputConsumer) throws ProjectBuildException { + long start = 0; try { JpsGroovySettings settings = JpsGroovySettings.getSettings(context.getProjectDescriptor().getProject()); @@ -102,8 +108,10 @@ public class GroovyBuilder extends ModuleLevelBuilder { return ExitCode.ABORT; } + start = System.currentTimeMillis(); final Set<String> toCompilePaths = getPathsToCompile(toCompile); - + boolean optimizeClassLoading = ourOptimizeThreshold != 0 && toCompilePaths.size() >= ourOptimizeThreshold; + Map<String, String> class2Src = buildClassToSourceMap(chunk, context, toCompilePaths, finalOutputs); final String encoding = context.getProjectDescriptor().getEncodingConfiguration().getPreferredModuleChunkEncoding(chunk); @@ -117,10 +125,18 @@ public class GroovyBuilder extends ModuleLevelBuilder { String compilerOutput = generationOutputs.get(chunk.representativeTarget()); String finalOutput = FileUtil.toSystemDependentName(finalOutputs.get(chunk.representativeTarget())); + + Collection<String> classpath = generateClasspath(context, chunk); + if (LOG.isDebugEnabled()) { + LOG.debug("Optimized class loading: " + optimizeClassLoading); + LOG.debug("Groovyc classpath: " + classpath); + } + final File tempFile = GroovycOSProcessHandler.fillFileWithGroovycParameters( - compilerOutput, toCompilePaths, finalOutput, class2Src, encoding, patchers + compilerOutput, toCompilePaths, finalOutput, class2Src, encoding, patchers, + optimizeClassLoading ? StringUtil.join(classpath, File.pathSeparator) : "" ); - final GroovycOSProcessHandler handler = runGroovyc(context, chunk, tempFile, settings); + final GroovycOSProcessHandler handler = runGroovyc(context, chunk, tempFile, settings, classpath, optimizeClassLoading); Map<ModuleBuildTarget, Collection<GroovycOSProcessHandler.OutputItem>> compiled = processCompiledFiles(context, chunk, generationOutputs, compilerOutput, handler); @@ -147,8 +163,11 @@ public class GroovyBuilder extends ModuleLevelBuilder { throw new ProjectBuildException(e); } finally { + if (start > 0 && LOG.isDebugEnabled()) { + LOG.debug(myBuilderName + " took " + (System.currentTimeMillis() - start) + " on " + chunk.getName()); + } if (!myForStubs) { - FILES_MARKED_DIRTY_FOR_NEXT_ROUND.set(context, null); + FILES_MARKED_DIRTY_FOR_NEXT_ROUND.set(context, null); } } } @@ -169,15 +188,24 @@ public class GroovyBuilder extends ModuleLevelBuilder { } private GroovycOSProcessHandler runGroovyc(final CompileContext context, - ModuleChunk chunk, + final ModuleChunk chunk, File tempFile, - final JpsGroovySettings settings) throws IOException { - ArrayList<String> classpath = new ArrayList<String>(generateClasspath(context, chunk)); - if (LOG.isDebugEnabled()) { - LOG.debug("Groovyc classpath: " + classpath); + final JpsGroovySettings settings, + Collection<String> compilationClassPath, + boolean optimizeClassLoading) throws IOException { + List<String> classpath = new ArrayList<String>(); + if (optimizeClassLoading) { + classpath.add(getGroovyRtRoot().getPath()); + classpath.add(ClasspathBootstrap.getResourcePath(Function.class)); + classpath.add(ClasspathBootstrap.getResourcePath(UrlClassLoader.class)); + classpath.add(ClasspathBootstrap.getResourceFile(THashMap.class).getPath()); + } else { + classpath.addAll(compilationClassPath); } - List<String> programParams = ContainerUtilRt.newArrayList(myForStubs ? "stubs" : "groovyc", tempFile.getPath()); + List<String> programParams = ContainerUtilRt.newArrayList(optimizeClassLoading ? GroovyRtConstants.OPTIMIZE : "do_not_optimize", + myForStubs ? "stubs" : "groovyc", + tempFile.getPath()); if (settings.invokeDynamic) { programParams.add("--indy"); } @@ -203,7 +231,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { final Process process = Runtime.getRuntime().exec(ArrayUtil.toStringArray(cmd)); final Consumer<String> updater = new Consumer<String>() { public void consume(String s) { - context.processMessage(new ProgressMessage(s)); + context.processMessage(new ProgressMessage(s + " [" + chunk.getPresentableShortName() + "]")); } }; final GroovycOSProcessHandler handler = new GroovycOSProcessHandler(process, updater) { @@ -403,7 +431,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { callback.associate(outputPath, sourcePath, new ClassReader(FileUtil.loadFileBytes(outputFile))); } catch (Throwable e) { - // need this to make sure that unexpected errors in, for example, ASM will not ruin the compilation + // need this to make sure that unexpected errors in, for example, ASM will not ruin the compilation final String message = "Class dependency information may be incomplete! Error parsing generated class " + item.outputPath; LOG.info(message, e); context.processMessage(new CompilerMessage( diff --git a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOSProcessHandler.java b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOSProcessHandler.java index 9a5a3d0bce25..a03067d99e61 100644 --- a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOSProcessHandler.java +++ b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOSProcessHandler.java @@ -219,10 +219,12 @@ public class GroovycOSProcessHandler extends BaseOSProcessHandler { if (unparsedBuffer.length() != 0) { String msg = unparsedBuffer.toString(); if (msg.contains(GroovyRtConstants.NO_GROOVY)) { - msg = "Cannot compile Groovy files: no Groovy library is defined for module '" + moduleName + "'"; + messages.add(new CompilerMessage("", BuildMessage.Kind.ERROR, + "Cannot compile Groovy files: no Groovy library is defined for module '" + moduleName + "'")); + } else { + messages.add(new CompilerMessage("Groovyc", BuildMessage.Kind.INFO, msg)); } - messages.add(new CompilerMessage("Groovyc", BuildMessage.Kind.INFO, msg)); } final int exitValue = getProcess().exitValue(); @@ -245,11 +247,17 @@ public class GroovycOSProcessHandler extends BaseOSProcessHandler { public static File fillFileWithGroovycParameters(final String outputDir, final Collection<String> changedSources, String finalOutput, - Map<String, String> class2Src, @Nullable final String encoding, List<String> patchers) throws IOException { + Map<String, String> class2Src, + @Nullable final String encoding, + List<String> patchers, + String classpath) throws IOException { File tempFile = FileUtil.createTempFile("ideaGroovyToCompile", ".txt", true); final Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempFile))); try { + writer.write(classpath); + writer.write("\n"); + for (String file : changedSources) { writer.write(GroovyRtConstants.SRC_FILE + "\n"); writer.write(file); diff --git a/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/GroovyRtConstants.java b/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/GroovyRtConstants.java index d146db0caa35..37583ddc96e4 100644 --- a/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/GroovyRtConstants.java +++ b/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/GroovyRtConstants.java @@ -36,4 +36,5 @@ public class GroovyRtConstants { public static final String PRESENTABLE_MESSAGE = "@#$%@# Presentable:"; public static final String CLEAR_PRESENTABLE = "$@#$%^ CLEAR_PRESENTABLE"; public static final String NO_GROOVY = "Cannot compile Groovy files: no Groovy library is defined"; + public static final String OPTIMIZE = "optimize"; } diff --git a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/DependentGroovycRunner.java b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/DependentGroovycRunner.java index 835c91d2d153..bb374cdfcdf4 100644 --- a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/DependentGroovycRunner.java +++ b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/DependentGroovycRunner.java @@ -39,7 +39,8 @@ import java.util.*; * @author peter */ public class DependentGroovycRunner { - static boolean runGroovyc(boolean forStubs, File argsFile) { + public static boolean runGroovyc(boolean forStubs, String argsPath) { + File argsFile = new File(argsPath); final CompilerConfiguration config = new CompilerConfiguration(); config.setClasspath(""); config.setOutput(new PrintWriter(System.err)); @@ -113,8 +114,9 @@ public class DependentGroovycRunner { stream = new FileInputStream(argsFile); reader = new BufferedReader(new InputStreamReader(stream)); - String line; + reader.readLine(); // skip classpath + String line; while ((line = reader.readLine()) != null) { if (!GroovyRtConstants.SRC_FILE.equals(line)) { break; diff --git a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovyCompilerUtil.java b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovyCompilerUtil.java deleted file mode 100644 index fc7a74c0ec91..000000000000 --- a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovyCompilerUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2000-2008 JetBrains s.r.o. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.groovy.compiler.rt; - -import org.codehaus.groovy.control.CompilerConfiguration; - -import java.net.URL; -import java.net.MalformedURLException; -import java.util.List; -import java.io.File; - -/** - * @author ilyas - */ -public class GroovyCompilerUtil { - static URL[] convertClasspathToUrls(CompilerConfiguration compilerConfiguration) { - try { - return classpathAsUrls(compilerConfiguration); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } - - static URL[] classpathAsUrls(CompilerConfiguration compilerConfiguration) throws MalformedURLException { - List classpath = compilerConfiguration.getClasspath(); - URL[] classpathUrls = new URL[classpath.size()]; - for (int i = 0; i < classpathUrls.length; i++) { - String classpathEntry = (String) classpath.get(i); - classpathUrls[i] = new File(classpathEntry).toURI().toURL(); - } - return classpathUrls; - } -} diff --git a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovycRunner.java b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovycRunner.java index 3d7e8eb5dd80..aaa42bca43c3 100644 --- a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovycRunner.java +++ b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovycRunner.java @@ -15,7 +15,16 @@ package org.jetbrains.groovy.compiler.rt; +import com.intellij.util.lang.UrlClassLoader; +import sun.misc.URLClassPath; + +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.*; /** * @author: Dmitry.Krasilschikov @@ -57,24 +66,28 @@ public class GroovycRunner { } */ - if (args.length != 2) { - if (args.length != 3 || !"--indy".equals(args[2])) { + if (args.length != 3) { + if (args.length != 4 || !"--indy".equals(args[3])) { System.err.println("There is no arguments for groovy compiler"); System.exit(1); } System.setProperty("groovy.target.indy", "true"); } - final boolean forStubs = "stubs".equals(args[0]); - final File argsFile = new File(args[1]); + final boolean optimize = GroovyRtConstants.OPTIMIZE.equals(args[0]); + final boolean forStubs = "stubs".equals(args[1]); + String argPath = args[2]; - if (!argsFile.exists()) { + if (!new File(argPath).exists()) { System.err.println("Arguments file for groovy compiler not found"); System.exit(1); } + ClassLoader loader = optimize ? buildMainLoader(argPath) : GroovycRunner.class.getClassLoader(); + Thread.currentThread().setContextClassLoader(loader); + try { - Class.forName("org.codehaus.groovy.control.CompilationUnit"); + Class.forName("org.codehaus.groovy.control.CompilationUnit", true, loader); } catch (Throwable e) { System.err.println(GroovyRtConstants.NO_GROOVY); @@ -82,7 +95,9 @@ public class GroovycRunner { } try { - DependentGroovycRunner.runGroovyc(forStubs, argsFile); + Class<?> aClass = Class.forName("org.jetbrains.groovy.compiler.rt.DependentGroovycRunner", true, loader); + Method method = aClass.getDeclaredMethod("runGroovyc", boolean.class, String.class); + method.invoke(null, forStubs, argPath); } catch (Throwable e) { e.printStackTrace(); @@ -102,4 +117,43 @@ public class GroovycRunner { } */ } + + private static ClassLoader buildMainLoader(String argsPath) { + Set<URL> bootstrapUrls = new HashSet<URL>(); + try { + Method method = ClassLoader.class.getDeclaredMethod("getBootstrapClassPath"); + method.setAccessible(true); + URLClassPath ucp = (URLClassPath)method.invoke(null); + Collections.addAll(bootstrapUrls, ucp.getURLs()); + } + catch (Exception e) { + e.printStackTrace(); + } + + final List<URL> urls = new ArrayList<URL>(); + try { + //noinspection IOResourceOpenedButNotSafelyClosed + BufferedReader reader = new BufferedReader(new FileReader(argsPath)); + String classpath = reader.readLine(); + for (String s : classpath.split(File.pathSeparator)) { + URL url = new File(s).toURI().toURL(); + if (!bootstrapUrls.contains(url)) { + urls.add(url); + } + } + reader.close(); + } + catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + + final ClassLoader[] ref = new ClassLoader[1]; + new Runnable() { + public void run() { + ref[0] = UrlClassLoader.build().urls(urls).useCache().get(); + } + }.run(); + return ref[0]; + } } diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 45fde1fd9fcc..c7965371c064 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -79,6 +79,7 @@ <extensionPoint name="convertToJava.customMethodInvocator" interface="org.jetbrains.plugins.groovy.refactoring.convertToJava.invocators.CustomMethodInvocator"/> + <extensionPoint name="signatureHintProcessor" interface="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.SignatureHintProcessor"/> </extensionPoints> <extensions defaultExtensionNs="org.intellij.groovy"> @@ -150,7 +151,30 @@ <variableEnhancer implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer"/> <variableEnhancer implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureAsAnonymousParameterEnhancer"/> - + <variableEnhancer implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParamsEnhancer"/> + + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.FromStringHintProcessor"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.SimpleTypeHintProcessor"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.MapEntryOrKeyValueHintProcessor"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.FromAbstractTypeMethodsHintProcessor"/> + + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.FirstParamHintProcessor"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.FirstParamHintProcessor$FirstGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.FirstParamHintProcessor$SecondGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.FirstParamHintProcessor$ThirdGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.FirstParamHintProcessor$Component"/> + + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.SecondParamHintProcessor"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.SecondParamHintProcessor$FirstGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.SecondParamHintProcessor$SecondGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.SecondParamHintProcessor$ThirdGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.SecondParamHintProcessor$Component"/> + + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ThirdParamHintProcessor"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ThirdParamHintProcessor$FirstGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ThirdParamHintProcessor$SecondGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ThirdParamHintProcessor$ThirdGeneric"/> + <signatureHintProcessor implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ThirdParamHintProcessor$Component"/> <typeConverter implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrContainerTypeConverter"/> <typeConverter implementation="org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrStringTypeConverter"/> diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index dee417b1a58a..4f7ebf4bbcd4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -168,9 +168,12 @@ public class GroovyAnnotator extends GroovyElementVisitor { @Override public void visitNamedArgument(GrNamedArgument argument) { - final PsiElement parent = argument.getParent().getParent(); - if (parent instanceof GrIndexProperty) { - myHolder.createErrorAnnotation(argument, GroovyBundle.message("named.arguments.are.not.allowed.inside.index.operations")); + PsiElement parent = argument.getParent(); + if (parent instanceof GrArgumentList) { + final PsiElement pparent = parent.getParent(); + if (pparent instanceof GrIndexProperty) { + myHolder.createErrorAnnotation(argument, GroovyBundle.message("named.arguments.are.not.allowed.inside.index.operations")); + } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java index a99f62d9b2c9..4ab96f047175 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.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. @@ -49,7 +49,6 @@ import org.jetbrains.plugins.groovy.refactoring.ui.MethodOrClosureScopeChooser; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Set; /** * @author Max Medvedev @@ -138,9 +137,9 @@ public class CreateParameterFromUsageFix extends Intention implements MethodOrCl if (project.isDisposed()) return; final String name = ref.getReferenceName(); - final Set<PsiType> types = GroovyExpectedTypesProvider.getDefaultExpectedTypes(ref); + final List<PsiType> types = GroovyExpectedTypesProvider.getDefaultExpectedTypes(ref); - PsiType unboxed = types.isEmpty() ? null : TypesUtil.unboxPrimitiveTypeWrapper(types.iterator().next()); + PsiType unboxed = types.isEmpty() ? null : TypesUtil.unboxPrimitiveTypeWrapper(types.get(0)); @NotNull final PsiType type = unboxed != null ? unboxed : PsiType.getJavaLangObject(ref.getManager(), ref.getResolveScope()); if (method instanceof GrMethod) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties index 3d658f098b0e..c19311d13dec 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties @@ -109,4 +109,6 @@ change.lvalue.type=Change variable ''{0}'' type to ''{1}'' replace.qualified.name.with.import=Replace qualified name with import highlight.assignments.from.void=Highlight assignments from void type comments.count.as.content=Comments count as content -ignore.when.catch.parameter.is.named.ignore.or.ignored=Ignore when catch parameter is named ignore or ignored
\ No newline at end of file +ignore.when.catch.parameter.is.named.ignore.or.ignored=Ignore when catch parameter is named ignore or ignored +no.applicable.signature.found=No applicable signature found +expected.type.0=Expected {0}
\ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index 970b39123c7c..b0d47a0552b3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -24,6 +24,7 @@ import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; @@ -70,8 +71,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; @@ -79,6 +82,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer; +import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParamsEnhancer; import org.jetbrains.plugins.groovy.lang.psi.util.*; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; @@ -242,7 +246,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitReturnStatement(GrReturnStatement returnStatement) { - super.visitReturnStatement(returnStatement); final GrExpression value = returnStatement.getReturnValue(); if (value == null || isNewInstanceInitialingByTuple(value)) return; @@ -254,7 +257,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitExpression(GrExpression expression) { - super.visitExpression(expression); if (PsiUtil.isExpressionStatement(expression)) { final PsiType returnType = PsiImplUtil.inferReturnType(expression); final GrControlFlowOwner flowOwner = ControlFlowUtils.findControlFlowOwner(expression); @@ -274,8 +276,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitAssignmentExpression(GrAssignmentExpression assignment) { - super.visitAssignmentExpression(assignment); - GrExpression lValue = assignment.getLValue(); if (lValue instanceof GrIndexProperty) return; if (!PsiUtil.mightBeLValue(lValue)) return; @@ -363,8 +363,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitVariable(GrVariable variable) { - super.visitVariable(variable); - PsiType varType = variable.getType(); PsiElement parent = variable.getParent(); @@ -430,7 +428,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitNewExpression(GrNewExpression newExpression) { - super.visitNewExpression(newExpression); if (newExpression.getArrayCount() > 0) return; GrCodeReferenceElement refElement = newExpression.getReferenceElement(); @@ -502,7 +499,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitListOrMap(GrListOrMap listOrMap) { - super.visitListOrMap(listOrMap); final PsiReference reference = listOrMap.getReference(); if (!(reference instanceof LiteralConstructorReference)) return; @@ -515,7 +511,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitThrowStatement(GrThrowStatement throwStatement) { - super.visitThrowStatement(throwStatement); final GrExpression exception = throwStatement.getException(); if (exception != null) { @@ -557,7 +552,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitConstructorInvocation(GrConstructorInvocation invocation) { - super.visitConstructorInvocation(invocation); GrConstructorInvocationInfo info = new GrConstructorInvocationInfo(invocation); checkConstructorCall(info); checkNamedArgumentsType(info); @@ -565,8 +559,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitIndexProperty(GrIndexProperty expression) { - super.visitIndexProperty(expression); - checkIndexProperty(new GrIndexPropertyInfo(expression)); } @@ -651,25 +643,21 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { @Override public void visitMethodCallExpression(GrMethodCallExpression methodCallExpression) { - super.visitMethodCallExpression(methodCallExpression); checkMethodCall(new GrMethodCallInfo(methodCallExpression)); } @Override public void visitApplicationStatement(GrApplicationStatement applicationStatement) { - super.visitApplicationStatement(applicationStatement); checkMethodCall(new GrMethodCallInfo(applicationStatement)); } @Override public void visitBinaryExpression(GrBinaryExpression binary) { - super.visitBinaryExpression(binary); checkOperator(new GrBinaryExprInfo(binary)); } @Override public void visitEnumConstant(GrEnumConstant enumConstant) { - super.visitEnumConstant(enumConstant); GrEnumConstantInfo info = new GrEnumConstantInfo(enumConstant); checkConstructorCall(info); checkNamedArgumentsType(info); @@ -710,6 +698,60 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { } } + @Override + public void visitParameterList(final GrParameterList parameterList) { + PsiElement parent = parameterList.getParent(); + if (parent instanceof GrClosableBlock) { + + GrParameter[] parameters = parameterList.getParameters(); + if (parameters.length > 0) { + List<PsiType[]> signatures = ClosureParamsEnhancer.findFittingSignatures((GrClosableBlock)parent); + final List<PsiType> paramTypes = ContainerUtil.map(parameters, new Function<GrParameter, PsiType>() { + @Override + public PsiType fun(GrParameter parameter) { + return parameter.getType(); + } + }); + + if (signatures.size() > 1) { + PsiType[] fittingSignature = ContainerUtil.find(signatures, new Condition<PsiType[]>() { + @Override + public boolean value(PsiType[] types) { + for (int i = 0; i < types.length; i++) { + if (!typesAreEqual(types[i], paramTypes.get(i), parameterList)) { + return false; + } + } + return true; + } + }); + + if (fittingSignature == null) { + registerError(parameterList, GroovyInspectionBundle.message("no.applicable.signature.found")); + } + } + else if (signatures.size() == 1) { + PsiType[] types = signatures.get(0); + for (int i = 0; i < types.length; i++) { + GrTypeElement typeElement = parameters[i].getTypeElementGroovy(); + if (typeElement == null) continue; + PsiType expected = types[i]; + PsiType actual = paramTypes.get(i); + if (!typesAreEqual(expected, actual, parameterList)) { + registerError(typeElement, GroovyInspectionBundle.message("expected.type.0", expected.getPresentableText())); + } + } + } + } + } + } + + private static boolean typesAreEqual(@NotNull PsiType expected, @NotNull PsiType actual, @NotNull PsiElement context) { + return TypesUtil.isAssignableByMethodCallConversion(expected, actual, context) && + TypesUtil.isAssignableByMethodCallConversion(actual, expected, context); + } + + /** * checks only children of e */ @@ -1020,6 +1062,11 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { private void highlightUnknownArgs(@NotNull CallInfo info) { registerError(info.getElementToHighlight(), GroovyBundle.message("cannot.infer.argument.types"), LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.WEAK_WARNING); } + + @Override + public void visitElement(GroovyPsiElement element) { + //do nothing + } } @Nullable @@ -1108,12 +1155,6 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { Object... args) { registerError(location, (String)args[0], LocalQuickFix.EMPTY_ARRAY, highlightType); } - - - @Override - public void visitElement(GroovyPsiElement element) { - //do nothing - } } private static final ThreadLocal<AnnotatingVisitor> visitor = new ThreadLocal<AnnotatingVisitor>() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrReassignedInClosureLocalVarInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrReassignedInClosureLocalVarInspection.java index 82a688f9bd89..400c0a366970 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrReassignedInClosureLocalVarInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrReassignedInClosureLocalVarInspection.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. @@ -21,12 +21,16 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.codeInsight.GrReassignedLocalVarsChecker; import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; @@ -66,18 +70,38 @@ public class GrReassignedInClosureLocalVarInspection extends BaseInspection { final PsiElement resolved = referenceExpression.resolve(); if (!GroovyRefactoringUtil.isLocalVariable(resolved)) return; - if (isOtherTypeOrDifferent(referenceExpression, (GrVariable)resolved) ) { - final String message = message("local.var.0.is.reassigned", ((GrNamedElement)resolved).getName()); + final PsiType checked = GrReassignedLocalVarsChecker.getReassignedVarType(referenceExpression, false); + if (checked == null) return; + + final GrControlFlowOwner varFlowOwner = ControlFlowUtils.findControlFlowOwner(resolved); + final GrControlFlowOwner refFlorOwner = ControlFlowUtils.findControlFlowOwner(referenceExpression); + if (isOtherScopeAndType(referenceExpression, checked, varFlowOwner, refFlorOwner)) { + String flowDescription = getFlowDescription(refFlorOwner); + final String message = message("local.var.0.is.reassigned", ((GrNamedElement)resolved).getName(), flowDescription); registerError(referenceExpression, message, LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); } } }; } - private static boolean isOtherTypeOrDifferent(@NotNull GrReferenceExpression referenceExpression, GrVariable resolved) { - if (ControlFlowUtils.findControlFlowOwner(referenceExpression) != ControlFlowUtils.findControlFlowOwner(resolved)) return true; + private static boolean isOtherScopeAndType(GrReferenceExpression referenceExpression, + PsiType checked, + GrControlFlowOwner varFlowOwner, + GrControlFlowOwner refFlorOwner) { + return varFlowOwner != refFlorOwner && !TypesUtil.isAssignable(referenceExpression.getType(), checked, referenceExpression); + } - final PsiType currentType = referenceExpression.getType(); - return currentType != null && currentType != PsiType.NULL && !ControlFlowUtils.findAccess(resolved, referenceExpression, false, true).isEmpty(); + private static String getFlowDescription(GrControlFlowOwner refFlorOwner) { + String flowDescription; + if (refFlorOwner instanceof GrClosableBlock) { + flowDescription = message("closure"); + } + else if (refFlorOwner instanceof GrAnonymousClassDefinition) { + flowDescription = message("anonymous.class"); + } + else { + flowDescription = message("other.scope"); + } + return flowDescription; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java index 31a97407fd13..78e3886b7842 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.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. @@ -49,7 +49,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; /** * @author ven @@ -125,9 +124,7 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool { } } else { - final Set<PsiType> expectedTypes = GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure); - - for (PsiType expectedType : expectedTypes) { + for (PsiType expectedType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure)) { if (TypesUtil.isPsiClassTypeToClosure(expectedType)) { PsiType[] parameters = ((PsiClassType)expectedType).getParameters(); if (parameters.length == 1) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUntypedAccessInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUntypedAccessInspection.java index d0b051e31d60..f4b380bd966f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUntypedAccessInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUntypedAccessInspection.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. @@ -27,6 +27,7 @@ import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import static org.jetbrains.plugins.groovy.annotator.GrHighlightUtil.isDeclarationAssignment; @@ -35,8 +36,37 @@ import static org.jetbrains.plugins.groovy.annotator.GrHighlightUtil.isDeclarati */ public class GroovyUntypedAccessInspection extends BaseInspection { + @NotNull protected BaseInspectionVisitor buildVisitor() { - return new Visitor(); + return new BaseInspectionVisitor() { + @Override + public void visitReferenceExpression(GrReferenceExpression refExpr) { + super.visitReferenceExpression(refExpr); + + if (PsiUtil.isThisOrSuperRef(refExpr)) return; + + GroovyResolveResult resolveResult = refExpr.advancedResolve(); + + PsiElement resolved = resolveResult.getElement(); + if (resolved != null) { + if (isDeclarationAssignment(refExpr) || resolved instanceof PsiPackage) return; + } + else { + GrExpression qualifier = refExpr.getQualifierExpression(); + if (qualifier == null && isDeclarationAssignment(refExpr)) return; + } + + final PsiType refExprType = refExpr.getType(); + if (refExprType == null) { + if (resolved != null) { + registerError(refExpr); + } + } + else if (refExprType instanceof PsiClassType && ((PsiClassType)refExprType).resolve() == null) { + registerError(refExpr); + } + } + }; } @Nls @@ -55,31 +85,4 @@ public class GroovyUntypedAccessInspection extends BaseInspection { protected String buildErrorString(Object... args) { return "Cannot determine type of '#ref'"; } - - private static class Visitor extends BaseInspectionVisitor { - @Override - public void visitReferenceExpression(GrReferenceExpression refExpr) { - super.visitReferenceExpression(refExpr); - GroovyResolveResult resolveResult = refExpr.advancedResolve(); - - PsiElement resolved = resolveResult.getElement(); - if (resolved != null) { - if (isDeclarationAssignment(refExpr) || resolved instanceof PsiPackage) return; - } - else { - GrExpression qualifier = refExpr.getQualifierExpression(); - if (qualifier == null && isDeclarationAssignment(refExpr)) return; - } - - final PsiType refExprType = refExpr.getType(); - if (refExprType == null) { - if (resolved != null) { - registerError(refExpr); - } - } - else if (refExprType instanceof PsiClassType && ((PsiClassType)refExprType).resolve() == null) { - registerError(refExpr); - } - } - } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerBase.java index 69450a8460f4..505d88b0e4dc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerBase.java @@ -194,7 +194,7 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler { try { fileWithParameters = GroovycOSProcessHandler .fillFileWithGroovycParameters(outputDir.getPath(), paths2Compile, FileUtil.toSystemDependentName(finalOutputDir.getPath()), - class2Src, encoding, patchers); + class2Src, encoding, patchers, ""); } catch (IOException e) { LOG.info(e); @@ -202,6 +202,7 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler { return; } + parameters.getProgramParametersList().add("do_not_optimize"); parameters.getProgramParametersList().add(forStubs ? "stubs" : "groovyc"); parameters.getProgramParametersList().add(fileWithParameters.getPath()); if (compilerConfiguration.isInvokeDynamic()) { @@ -253,7 +254,7 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler { if (sourceVirtualFile == null) { continue; } - + if (indicator != null) { indicator.setText2(sourceVirtualFile.getName()); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java index 8f9958b2a024..5470ed0490d9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.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. @@ -129,6 +129,8 @@ public class CustomMembersGenerator extends GroovyObjectSupport implements GdslM Methods to add new behavior *********************************************************** */ public void property(Map<Object, Object> args) { + if (args == null) return; + String name = (String)args.get("name"); Object type = args.get("type"); Object doc = args.get("doc"); @@ -156,6 +158,8 @@ public class CustomMembersGenerator extends GroovyObjectSupport implements GdslM } public void constructor(Map<Object, Object> args) { + if (args == null) return; + args.put("constructor", true); method(args); } @@ -190,8 +194,7 @@ public class CustomMembersGenerator extends GroovyObjectSupport implements GdslM ContainerUtil.map(argTypes, new Function<PsiType, Object>() { @Override public Object fun(PsiType type) { - String canonical = type.getCanonicalText(); - return canonical != null ? canonical : type.getPresentableText(); + return type.getCanonicalText(); } }, types); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index 82cfe11991df..b852cd2159c1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -28,6 +28,7 @@ import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.io.FileUtil; @@ -131,11 +132,13 @@ public class GroovyDslFileIndex extends ScalarIndexExtension<String> { return myDataIndexer; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new MyInputFilter(); @@ -438,7 +441,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension<String> { @Override public Result<List<GroovyDslScript>> compute() { if (ourGdslStopped) { - return Result.create(Collections.<GroovyDslScript>emptyList(), Collections.emptyList()); + return Result.create(Collections.<GroovyDslScript>emptyList(), ModificationTracker.NEVER_CHANGED); } int count = 0; @@ -513,7 +516,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension<String> { } @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return "gdsl".equals(file.getExtension()); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/blocks/GroovyBlockGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/blocks/GroovyBlockGenerator.java index bba144184a7a..8a98eeff03ea 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/blocks/GroovyBlockGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/blocks/GroovyBlockGenerator.java @@ -405,7 +405,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes { PsiElement psi = child.getPsi(); if (psi instanceof GrLabeledStatement) { alignGroup(currentGroup, spock, classLevel); - currentGroup = ContainerUtil.newArrayList(/*(GrStatement)psi*/); + currentGroup = ContainerUtil.newArrayList(); spock = true; } else if (currentGroup != null && spock && isTablePart(psi)) { @@ -428,6 +428,10 @@ public class GroovyBlockGenerator implements GroovyElementTypes { currentGroup = null; } } + + if (currentGroup != null) { + alignGroup(currentGroup, spock, classLevel); + } } private boolean shouldSkip(boolean classLevel, PsiElement psi) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java index 4d1f239101b6..c9f6f98c3132 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java @@ -287,8 +287,7 @@ public class GroovySmartCompletionContributor extends CompletionContributor { placeToInferType = (GrExpression)expression.getParent(); } - final Set<PsiType> types = GroovyExpectedTypesProvider.getDefaultExpectedTypes(placeToInferType); - for (PsiType type : types) { + for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(placeToInferType)) { if (type instanceof PsiArrayType) { final PsiType _type = GenericsUtil.eliminateWildcards(type); final LookupItem item = PsiTypeLookupItem.createLookupItem(_type, place, PsiTypeLookupItem.isDiamond(_type), ChooseTypeExpression.IMPORT_FIXER); @@ -307,7 +306,7 @@ public class GroovySmartCompletionContributor extends CompletionContributor { final List<PsiClassType> expectedClassTypes = new SmartList<PsiClassType>(); - for (PsiType psiType : types) { + for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(placeToInferType)) { if (psiType instanceof PsiClassType) { PsiType type = GenericsUtil.eliminateWildcards(JavaCompletionUtil.originalize(psiType)); final PsiClassType classType = (PsiClassType)type; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java index 10e5c0babb0d..e2e36d143e84 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java @@ -26,7 +26,6 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.hash.HashSet; import com.intellij.util.text.CharArrayUtil; -import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil; @@ -387,11 +386,11 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandlerWithTabAc for (int j = 0; j < numParams; j++) { PsiParameter param = params[j]; - int startOffset = XmlStringUtil.escapeString(buffer.toString()).length(); + int startOffset = buffer.length(); appendParameterText(param, substitutor, buffer); - int endOffset = XmlStringUtil.escapeString(buffer.toString()).length(); + int endOffset = buffer.length(); if (j < numParams - 1) { buffer.append(", "); @@ -420,7 +419,7 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandlerWithTabAc for (int i = 0; i < parameters.length; i++) { if (i > 0) buffer.append(", "); - int startOffset = XmlStringUtil.escapeString(buffer.toString()).length(); + int startOffset = buffer.length(); final PsiType psiType = parameters[i].getType(); if (psiType == null) { buffer.append("def"); @@ -430,7 +429,7 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandlerWithTabAc } buffer.append(' ').append(parameters[i].getName() != null ? parameters[i].getName() : "<unknown>"); - int endOffset = XmlStringUtil.escapeString(buffer.toString()).length(); + int endOffset = buffer.length(); if (context.isUIComponentEnabled() && (i == currentParameter || (i == parameters.length - 1 && ((GrClosureSignature)element).isVarargs() && currentParameter >= parameters.length))) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrField.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrField.java index 0946bd525ae6..6e3ea04a0805 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrField.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrField.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. @@ -41,7 +41,5 @@ public interface GrField extends GrVariable, GrMember, PsiField, GrTopLevelDefin @NotNull Map<String, NamedArgumentDescriptor> getNamedParameters(); - - void clearCaches(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java index 09ce7cc83ea9..1d541a0b83c2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java @@ -22,6 +22,7 @@ import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,14 +53,15 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; @@ -97,12 +99,14 @@ public class GroovyExpectedTypesProvider { }); } - public static Set<PsiType> getDefaultExpectedTypes(@NotNull GrExpression element) { - final LinkedHashSet<PsiType> result = new LinkedHashSet<PsiType>(); - for (TypeConstraint constraint : calculateTypeConstraints(element)) { - result.add(constraint.getDefaultType()); - } - return result; + public static List<PsiType> getDefaultExpectedTypes(@NotNull GrExpression element) { + TypeConstraint[] constraints = calculateTypeConstraints(element); + return ContainerUtil.map(constraints, new Function<TypeConstraint, PsiType>() { + @Override + public PsiType fun(TypeConstraint constraint) { + return constraint.getDefaultType(); + } + }); } private static class MyCalculator extends GroovyElementVisitor { @@ -176,8 +180,8 @@ public class GroovyExpectedTypesProvider { final GrClosableBlock[] closureArgs = methodCall.getClosureArguments(); if (ArrayUtil.contains(myExpression, closureArgs)) { final GrArgumentList argumentList = methodCall.getArgumentList(); - final GrNamedArgument[] namedArgs = argumentList == null ? GrNamedArgument.EMPTY_ARRAY : argumentList.getNamedArguments(); - final GrExpression[] expressionArgs = argumentList == null ? GrExpression.EMPTY_ARRAY : argumentList.getExpressionArguments(); + final GrNamedArgument[] namedArgs = argumentList.getNamedArguments(); + final GrExpression[] expressionArgs = argumentList.getExpressionArguments(); final GroovyResolveResult[] callVariants = ResolveUtil.getCallVariants(myExpression); processCallVariants(methodCall, callVariants, namedArgs, expressionArgs, closureArgs); } @@ -344,18 +348,32 @@ public class GroovyExpectedTypesProvider { @NotNull GrNamedArgument[] namedArguments, @NotNull GrExpression[] expressionArguments, @NotNull GrClosableBlock[] closureArguments) { + + List<Pair<PsiParameter, PsiType>> expectedParams = + ResolveUtil.collectExpectedParamsByArg(place, variants, namedArguments, expressionArguments, closureArguments, myExpression); + + collectExpectedTypeFromPossibleParams(expectedParams); + } + + private void collectExpectedTypeFromPossibleParams(List<Pair<PsiParameter, PsiType>> expectedParams) { List<TypeConstraint> constraints = ContainerUtil.newArrayList(); - for (GroovyResolveResult variant : variants) { - final Map<GrExpression, Pair<PsiParameter, PsiType>> map = GrClosureSignatureUtil.mapArgumentsToParameters( - variant, place, true, true, namedArguments, expressionArguments, closureArguments - ); - addConstraintsFromMap(constraints, map); + for (Pair<PsiParameter, PsiType> pair : expectedParams) { + final PsiType type = pair.second; + if (type != null) { + + constraints.add(SubtypeConstraint.create(type)); + + if (type instanceof PsiArrayType && pair.first.isVarArgs()) { + constraints.add(SubtypeConstraint.create(((PsiArrayType)type).getComponentType())); + } + } } if (!constraints.isEmpty()) { myResult = constraints.toArray(new TypeConstraint[constraints.size()]); } } + @Override public void visitBinaryExpression(GrBinaryExpression expression) { final IElementType type = expression.getOperationTokenType(); @@ -382,7 +400,8 @@ public class GroovyExpectedTypesProvider { } } else { //myExpression == right - processCallVariants(expression, callVariants, GrNamedArgument.EMPTY_ARRAY, new GrExpression[]{myExpression}, GrClosableBlock.EMPTY_ARRAY); + processCallVariants(expression, callVariants, GrNamedArgument.EMPTY_ARRAY, new GrExpression[]{myExpression}, + GrClosableBlock.EMPTY_ARRAY); } } @@ -398,22 +417,6 @@ public class GroovyExpectedTypesProvider { } } - private void addConstraintsFromMap(List<TypeConstraint> constraints, Map<GrExpression, Pair<PsiParameter, PsiType>> map) { - if (map == null) return; - - final Pair<PsiParameter, PsiType> pair = map.get(myExpression); - if (pair == null) return; - - final PsiType type = pair.second; - if (type == null) return; - - constraints.add(SubtypeConstraint.create(type)); - - if (type instanceof PsiArrayType && pair.first.isVarArgs()) { - constraints.add(SubtypeConstraint.create(((PsiArrayType)type).getComponentType())); - } - } - public void visitAssignmentExpression(GrAssignmentExpression expression) { GrExpression rValue = expression.getRValue(); GrExpression lValue = expression.getLValue(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java index 387db8400b1e..b43ee28c1ece 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.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. @@ -15,11 +15,11 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl; -import com.intellij.psi.PsiAnnotation; -import com.intellij.psi.PsiAnnotationMemberValue; -import com.intellij.psi.PsiLiteral; +import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; /** * @author Max Medvedev @@ -54,4 +54,52 @@ public class GrAnnotationUtil { } return null; } + + @Nullable + public static PsiClass inferClassAttribute(@NotNull PsiAnnotation annotation, @NotNull String attributeName) { + final PsiAnnotationMemberValue targetValue = annotation.findAttributeValue(attributeName); + if (targetValue instanceof PsiClassObjectAccessExpression) { + PsiType type = ((PsiClassObjectAccessExpression)targetValue).getOperand().getType(); + if (type instanceof PsiClassType) { + return ((PsiClassType)type).resolve(); + } + } + else if (targetValue instanceof GrReferenceExpression) { + if ("class".equals(((GrReferenceExpression)targetValue).getReferenceName())) { + GrExpression qualifier = ((GrReferenceExpression)targetValue).getQualifier(); + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); + if (resolved instanceof PsiClass) { + return (PsiClass)resolved; + } + } + } + PsiElement resolved = ((GrReferenceExpression)targetValue).resolve(); + if (resolved instanceof PsiClass) return (PsiClass)resolved; + } + return null; + } + + @Nullable + public static PsiType extractClassTypeFromClassAttributeValue(PsiAnnotationMemberValue targetValue) { + if (targetValue instanceof PsiClassObjectAccessExpression) { + return ((PsiClassObjectAccessExpression)targetValue).getOperand().getType(); + } + else if (targetValue instanceof GrReferenceExpression) { + if ("class".equals(((GrReferenceExpression)targetValue).getReferenceName())) { + GrExpression qualifier = ((GrReferenceExpression)targetValue).getQualifier(); + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); + if (resolved instanceof PsiClass) { + return qualifier.getType(); + } + } + } + PsiElement resolved = ((GrReferenceExpression)targetValue).resolve(); + if (resolved instanceof PsiClass) { + return ((GrReferenceExpression)targetValue).getType(); + } + } + return null; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java index e2efdadc0445..efddced80d5a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java @@ -56,7 +56,7 @@ public class GrClosureType extends GrLiteralClassType { @NotNull GlobalSearchScope scope, @NotNull JavaPsiFacade facade, @NotNull GrSignature signature, - @NotNull PsiType[] typeArgs) { + @Nullable PsiType[] typeArgs) { super(level, scope, facade); mySignature = signature; @@ -132,7 +132,7 @@ public class GrClosureType extends GrLiteralClassType { @Override public boolean equalsToText(@NotNull @NonNls String text) { - return text != null && text.equals(GroovyCommonClassNames.GROOVY_LANG_CLOSURE); + return text.equals(GroovyCommonClassNames.GROOVY_LANG_CLOSURE); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrFieldImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrFieldImpl.java index 7e852036dc04..50ccc2327086 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrFieldImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrFieldImpl.java @@ -23,6 +23,9 @@ import com.intellij.psi.impl.ResolveScopeManager; import com.intellij.psi.presentation.java.JavaPresentationUtil; import com.intellij.psi.search.SearchScope; import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; import com.intellij.ui.LayeredIcon; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; @@ -59,8 +62,6 @@ import java.util.Map; * Date: 25.05.2007 */ public class GrFieldImpl extends GrVariableBaseImpl<GrFieldStub> implements GrField, StubBasedPsiElement<GrFieldStub> { - private volatile GrAccessorMethod mySetter; - private volatile GrAccessorMethod[] myGetters; public GrFieldImpl(@NotNull ASTNode node) { super(node); @@ -188,24 +189,24 @@ public class GrFieldImpl extends GrVariableBaseImpl<GrFieldStub> implements GrFi } public GrAccessorMethod getSetter() { - if (mySetter == null) { - mySetter = GrAccessorMethodImpl.createSetterMethod(this); - } - return mySetter; - } - - public void clearCaches() { - mySetter = null; - myGetters = null; + return CachedValuesManager.getCachedValue(this, new CachedValueProvider<GrAccessorMethod>() { + @Nullable + @Override + public Result<GrAccessorMethod> compute() { + return Result.create(GrAccessorMethodImpl.createSetterMethod(GrFieldImpl.this), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }); } @NotNull public GrAccessorMethod[] getGetters() { - if (myGetters == null) { - myGetters = GrAccessorMethodImpl.createGetterMethods(this); - } - - return myGetters; + return CachedValuesManager.getCachedValue(this, new CachedValueProvider<GrAccessorMethod[]>() { + @Nullable + @Override + public Result<GrAccessorMethod[]> compute() { + return Result.create(GrAccessorMethodImpl.createGetterMethods(GrFieldImpl.this), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }); } @NotNull @@ -240,7 +241,8 @@ public class GrFieldImpl extends GrVariableBaseImpl<GrFieldStub> implements GrFi } @Nullable - public Icon getIcon(int flags) { + @Override + protected Icon getElementIcon(@IconFlags int flags) { Icon superIcon = JetgroovyIcons.Groovy.Field; if (!isProperty()) return superIcon; LayeredIcon rowIcon = new LayeredIcon(2); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrVariableDeclarationImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrVariableDeclarationImpl.java index 990876dea044..6e312234decb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrVariableDeclarationImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrVariableDeclarationImpl.java @@ -1,6 +1,6 @@ /* - * 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. @@ -25,7 +25,6 @@ import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.EmptyStub; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; -import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -212,7 +211,7 @@ public class GrVariableDeclarationImpl extends GrStubElementBase<EmptyStub> impl @Nullable @Override public Result<PsiReference> compute() { - return Result.create(getReferenceInner(), PsiModificationTracker.MODIFICATION_COUNT); + return Result.create(getReferenceInner(), getContainingFile()); } }); } @@ -226,20 +225,40 @@ public class GrVariableDeclarationImpl extends GrStubElementBase<EmptyStub> impl final GrVariable[] variables = getVariables(); if (variables.length == 0) return null; - final PsiElement resolved = variables[0]; - return new PsiReferenceBase<GrVariableDeclaration>(this, range, true) { - @Nullable - @Override - public PsiElement resolve() { - return resolved; - } - - @NotNull - @Override - public Object[] getVariants() { - return EMPTY_ARRAY; - } - }; + final GrVariable resolved = variables[0]; + final PsiType inferredType = resolved.getTypeGroovy(); + if (inferredType == null) return null; + + if (inferredType instanceof PsiClassType) { + return new PsiReferenceBase<GrVariableDeclaration>(this, range, true) { + @Nullable + @Override + public PsiElement resolve() { + return ((PsiClassType)inferredType).resolve(); + } + + @NotNull + @Override + public Object[] getVariants() { + return EMPTY_ARRAY; + } + }; + } + else { + return new PsiReferenceBase<GrVariableDeclaration>(this, range, true) { + @Nullable + @Override + public PsiElement resolve() { + return resolved; + } + + @NotNull + @Override + public Object[] getVariants() { + return EMPTY_ARRAY; + } + }; + } } private TextRange getRangeForReference() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 3119608176ff..825f4d86fdd7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -484,10 +484,11 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi @Override protected GrReferenceExpression bindWithQualifiedRef(@NotNull String qName) { + GrReferenceExpression qualifiedRef = GroovyPsiElementFactory.getInstance(getProject()).createReferenceExpressionFromText(qName); final GrTypeArgumentList list = getTypeArgumentList(); - final String typeArgs = (list != null) ? list.getText() : ""; - final String text = qName + typeArgs; - GrReferenceExpression qualifiedRef = GroovyPsiElementFactory.getInstance(getProject()).createReferenceExpressionFromText(text); + if (list != null) { + qualifiedRef.getNode().addChild(list.copy().getNode()); + } getNode().getTreeParent().replaceChild(getNode(), qualifiedRef.getNode()); return qualifiedRef; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionBodyBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionBodyBase.java index ea18c1b94822..1c9bdc9a1b18 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionBodyBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionBodyBase.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. @@ -22,6 +22,7 @@ import com.intellij.psi.StubBasedPsiElement; import com.intellij.psi.stubs.EmptyStub; import com.intellij.psi.stubs.IStubElementType; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; @@ -39,15 +40,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; import org.jetbrains.plugins.groovy.lang.psi.impl.GrStubElementBase; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import java.util.ArrayList; import java.util.List; /** * @author: Dmitry.Krasilschikov, ilyas */ public abstract class GrTypeDefinitionBodyBase extends GrStubElementBase<EmptyStub> implements GrTypeDefinitionBody { - private GrField[] myFields = null; - public GrTypeDefinitionBodyBase(@NotNull ASTNode node) { super(node); } @@ -61,14 +59,6 @@ public abstract class GrTypeDefinitionBodyBase extends GrStubElementBase<EmptySt return getParentByStub(); } - public void subtreeChanged() { - super.subtreeChanged(); - myFields = null; - for (GrField field : getFields()) { - field.clearCaches(); - } - } - public abstract void accept(GroovyElementVisitor visitor); public String toString() { @@ -76,22 +66,18 @@ public abstract class GrTypeDefinitionBodyBase extends GrStubElementBase<EmptySt } public GrField[] getFields() { - if (myFields == null) { - GrVariableDeclaration[] declarations = getStubOrPsiChildren(GroovyElementTypes.VARIABLE_DEFINITION, GrVariableDeclaration.ARRAY_FACTORY); - if (declarations.length == 0) return GrField.EMPTY_ARRAY; - List<GrField> result = new ArrayList<GrField>(); - for (GrVariableDeclaration declaration : declarations) { - GrVariable[] variables = declaration.getVariables(); - for (GrVariable variable : variables) { - if (variable instanceof GrField) { - result.add((GrField) variable); - } + GrVariableDeclaration[] declarations = getStubOrPsiChildren(GroovyElementTypes.VARIABLE_DEFINITION, GrVariableDeclaration.ARRAY_FACTORY); + List<GrField> result = ContainerUtil.newArrayList(); + for (GrVariableDeclaration declaration : declarations) { + GrVariable[] variables = declaration.getVariables(); + for (GrVariable variable : variables) { + if (variable instanceof GrField) { + result.add((GrField)variable); } } - myFields = result.toArray(new GrField[result.size()]); } - return myFields; + return result.toArray(new GrField[result.size()]); } public GrMethod[] getMethods() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java index 0298021c626f..1c20805c3463 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.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. @@ -19,10 +19,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef; import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.RecursionGuard; -import com.intellij.openapi.util.RecursionManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; @@ -31,7 +28,6 @@ import com.intellij.psi.impl.*; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.IStubElementType; -import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; @@ -40,7 +36,6 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtilRt; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityIcons; -import com.intellij.util.containers.ContainerUtil; import icons.JetgroovyIcons; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -74,32 +69,21 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrTypeDefinitionStub; import org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; -import org.jetbrains.plugins.groovy.lang.resolve.ast.AstTransformContributor; import org.jetbrains.plugins.groovy.runner.GroovyRunnerUtil; -import org.jetbrains.plugins.groovy.util.LightCacheKey; import javax.swing.*; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; -import static org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil.*; +import static org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil.isClassEquivalentTo; /** * @author ilyas */ public abstract class GrTypeDefinitionImpl extends GrStubElementBase<GrTypeDefinitionStub> implements GrTypeDefinition, StubBasedPsiElement<GrTypeDefinitionStub> { - private static final LightCacheKey<List<GrField>> AST_TRANSFORM_FIELD = LightCacheKey.createByJavaModificationCount(); - private static final RecursionGuard ourGuard = RecursionManager.createGuard("groovyMembers"); - - private volatile PsiClass[] myInnerClasses; - private volatile GrMethod[] myGroovyMethods; - private volatile PsiMethod[] myConstructors; - private volatile GrMethod[] myCodeConstructors; - - Key<CachedValue<PsiMethod[]>> CACHED_METHODS = Key.create("cached.type.definition.methods"); + private final GrTypeDefinitionMembersCache myCache = new GrTypeDefinitionMembersCache(this); public GrTypeDefinitionImpl(@NotNull ASTNode node) { super(node); @@ -331,150 +315,45 @@ public abstract class GrTypeDefinitionImpl extends GrStubElementBase<GrTypeDefin return GrClassImplUtil.findFieldByName(this, name, checkBases, false); } - private List<GrField> getSyntheticFields() { - List<GrField> fields = AST_TRANSFORM_FIELD.getCachedValue(this); - if (fields == null) { - final RecursionGuard.StackStamp stamp = ourGuard.markStack(); - fields = AstTransformContributor.runContributorsForFields(this); - if (stamp.mayCacheNow()) { - fields = AST_TRANSFORM_FIELD.putCachedValue(this, fields); - } - } - - return fields; - } - @NotNull public GrField[] getFields() { - GrField[] codeFields = getCodeFields(); - - List<GrField> fromAstTransform = getSyntheticFields(); - if (fromAstTransform.isEmpty()) return codeFields; - - GrField[] res = new GrField[codeFields.length + fromAstTransform.size()]; - System.arraycopy(codeFields, 0, res, 0, codeFields.length); - - for (int i = 0; i < fromAstTransform.size(); i++) { - res[codeFields.length + i] = fromAstTransform.get(i); - } - - return res; + return myCache.getFields(); } @NotNull public PsiMethod[] getMethods() { - CachedValue<PsiMethod[]> cached = getUserData(CACHED_METHODS); - if (cached == null) { - cached = CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<PsiMethod[]>() { - @Override - public Result<PsiMethod[]> compute() { - GrTypeDefinitionBody body = getBody(); - List<PsiMethod> result = new ArrayList<PsiMethod>(); - if (body != null) { - collectMethodsFromBody(body, result); - } - - for (PsiMethod method : AstTransformContributor.runContributorsForMethods(GrTypeDefinitionImpl.this)) { - addExpandingReflectedMethods(result, method); - } - - for (GrField field : getSyntheticFields()) { - ContainerUtil.addIfNotNull(result, field.getSetter()); - Collections.addAll(result, field.getGetters()); - } - return Result.create(result.toArray(new PsiMethod[result.size()]), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); - } - }, false); - putUserData(CACHED_METHODS, cached); - } - - - return cached.getValue(); + return myCache.getMethods(); } @NotNull public GrMethod[] getCodeMethods() { - GrMethod[] cached = myGroovyMethods; - if (cached == null) { - RecursionGuard.StackStamp stamp = ourGuard.markStack(); - GrTypeDefinitionBody body = getBody(); - cached = body != null ? body.getMethods() : GrMethod.EMPTY_ARRAY; - if (stamp.mayCacheNow()) { - myGroovyMethods = cached; - } - } - return cached; + return myCache.getCodeMethods(); } public void subtreeChanged() { - myInnerClasses = null; - myConstructors = null; - myCodeConstructors = null; - myGroovyMethods = null; + myCache.dropCaches(); super.subtreeChanged(); } @NotNull public PsiMethod[] getConstructors() { - PsiMethod[] cached = myConstructors; - if (cached == null) { - RecursionGuard.StackStamp stamp = ourGuard.markStack(); - List<PsiMethod> result = new ArrayList<PsiMethod>(); - for (final PsiMethod method : getMethods()) { - if (method.isConstructor()) { - addExpandingReflectedMethods(result, method); - } - } - - cached = result.toArray(new PsiMethod[result.size()]); - if (stamp.mayCacheNow()) { - myConstructors = cached; - } - } - return cached; + return myCache.getConstructors(); } @NotNull public GrMethod[] getCodeConstructors() { - GrMethod[] cached = myCodeConstructors; - if (cached == null) { - RecursionGuard.StackStamp stamp = ourGuard.markStack(); - List<GrMethod> result = new ArrayList<GrMethod>(); - for (final GrMethod method : getCodeMethods()) { - if (method.isConstructor()) { - result.add(method); - } - } - - cached = result.toArray(new GrMethod[result.size()]); - if (stamp.mayCacheNow()) { - myCodeConstructors = cached; - } - } - return cached; + return myCache.getCodeConstructors(); } @NotNull public PsiClass[] getInnerClasses() { - PsiClass[] inners = myInnerClasses; - if (inners == null) { - RecursionGuard.StackStamp stamp = ourGuard.markStack(); - final GrTypeDefinitionBody body = getBody(); - inners = body != null ? body.getInnerClasses() : PsiClass.EMPTY_ARRAY; - if (stamp.mayCacheNow()) { - myInnerClasses = inners; - } - } - - return inners; + return myCache.getInnerClasses(); } @NotNull public GrClassInitializer[] getInitializers() { GrTypeDefinitionBody body = getBody(); - if (body == null) return GrClassInitializer.EMPTY_ARRAY; - - return body.getInitializers(); + return body != null ? body.getInitializers() : GrClassInitializer.EMPTY_ARRAY; } @NotNull @@ -680,7 +559,8 @@ public abstract class GrTypeDefinitionImpl extends GrStubElementBase<GrTypeDefin } @Nullable - public Icon getIcon(int flags) { + @Override + protected Icon getElementIcon(@IconFlags int flags) { Icon icon = getIconInner(); final boolean isLocked = (flags & ICON_FLAG_READ_STATUS) != 0 && !isWritable(); RowIcon rowIcon = createLayeredIcon(this, icon, ElementPresentationUtil.getFlags(this, isLocked) | getFlagsInner()); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java new file mode 100644 index 000000000000..3a2ec2cfe6ef --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java @@ -0,0 +1,187 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef; + +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.ModificationTracker; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.resolve.ast.AstTransformContributor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT; +import static org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil.addExpandingReflectedMethods; +import static org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil.collectMethodsFromBody; + +/** + * Created by Max Medvedev on 03/03/14 + */ +public class GrTypeDefinitionMembersCache { + private static final Condition<PsiMethod> CONSTRUCTOR_CONDITION = new Condition<PsiMethod>() { + @Override + public boolean value(PsiMethod method) { + return method.isConstructor(); + } + }; + + private final MyModificationTracker myTreeChangeTracker = new MyModificationTracker(); + + private final GrTypeDefinition myDefinition; + + public GrTypeDefinitionMembersCache(GrTypeDefinition definition) { + myDefinition = definition; + } + + + public GrMethod[] getCodeMethods() { + return CachedValuesManager.getCachedValue(myDefinition, new CachedValueProvider<GrMethod[]>() { + @Nullable + @Override + public Result<GrMethod[]> compute() { + GrTypeDefinitionBody body = myDefinition.getBody(); + GrMethod[] methods = body != null ? body.getMethods() : GrMethod.EMPTY_ARRAY; + return Result.create(methods, myTreeChangeTracker); + } + }); + } + + public GrMethod[] getCodeConstructors() { + return CachedValuesManager.getCachedValue(myDefinition, new CachedValueProvider<GrMethod[]>() { + @Nullable + @Override + public Result<GrMethod[]> compute() { + GrTypeDefinitionBody body = myDefinition.getBody(); + GrMethod[] methods; + if (body != null) { + List<GrMethod> result = ContainerUtil.findAll(body.getMethods(), CONSTRUCTOR_CONDITION); + methods = result.toArray(new GrMethod[result.size()]); + } + else { + methods = GrMethod.EMPTY_ARRAY; + } + return Result.create(methods, myTreeChangeTracker); + } + }); + } + + public PsiMethod[] getConstructors() { + return CachedValuesManager.getCachedValue(myDefinition, new CachedValueProvider<PsiMethod[]>() { + @Nullable + @Override + public Result<PsiMethod[]> compute() { + List<PsiMethod> result = ContainerUtil.findAll(myDefinition.getMethods(), CONSTRUCTOR_CONDITION); + return Result.create(result.toArray(new PsiMethod[result.size()]), myTreeChangeTracker, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }); + } + + + public PsiClass[] getInnerClasses() { + return CachedValuesManager.getCachedValue(myDefinition, new CachedValueProvider<PsiClass[]>() { + @Nullable + @Override + public Result<PsiClass[]> compute() { + final GrTypeDefinitionBody body = myDefinition.getBody(); + PsiClass[] inners = body != null ? body.getInnerClasses() : PsiClass.EMPTY_ARRAY; + return Result.create(inners, myTreeChangeTracker); + } + }); + } + + public GrField[] getFields() { + return CachedValuesManager.getCachedValue(myDefinition, new CachedValueProvider<GrField[]>() { + @Nullable + @Override + public Result<GrField[]> compute() { + return Result.create(getFieldsImpl(), myTreeChangeTracker, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }); + } + + private GrField[] getFieldsImpl() { + GrField[] codeFields = myDefinition.getCodeFields(); + + List<GrField> fromAstTransform = getSyntheticFields(); + if (fromAstTransform.isEmpty()) return codeFields; + + GrField[] res = new GrField[codeFields.length + fromAstTransform.size()]; + System.arraycopy(codeFields, 0, res, 0, codeFields.length); + + for (int i = 0; i < fromAstTransform.size(); i++) { + res[codeFields.length + i] = fromAstTransform.get(i); + } + + return res; + } + + private List<GrField> getSyntheticFields() { + return CachedValuesManager.getCachedValue(myDefinition, new CachedValueProvider<List<GrField>>() { + @Nullable + @Override + public Result<List<GrField>> compute() { + return Result.create(AstTransformContributor.runContributorsForFields(myDefinition), myTreeChangeTracker, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }); + } + + public PsiMethod[] getMethods() { + return CachedValuesManager.getCachedValue(myDefinition, new CachedValueProvider<PsiMethod[]>() { + @Override + public Result<PsiMethod[]> compute() { + List<PsiMethod> result = new ArrayList<PsiMethod>(); + collectMethodsFromBody(myDefinition, result); + + for (PsiMethod method : AstTransformContributor.runContributorsForMethods(myDefinition)) { + addExpandingReflectedMethods(result, method); + } + + for (GrField field : getSyntheticFields()) { + ContainerUtil.addIfNotNull(result, field.getSetter()); + Collections.addAll(result, field.getGetters()); + } + return Result.create(result.toArray(new PsiMethod[result.size()]), myTreeChangeTracker, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }); + } + + public void dropCaches() { + myTreeChangeTracker.inc(); + } + + private static class MyModificationTracker implements ModificationTracker { + private long myCount = 0; + + @Override + public long getModificationCount() { + return myCount; + } + + public void inc() { + myCount++; + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java index b608f2994ddc..4fa96fe439f9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java @@ -297,8 +297,9 @@ public abstract class GrMethodBaseImpl extends GrStubElementBase<GrMethodStub> i return true; } + @Nullable @Override - public Icon getIcon(int flags) { + protected Icon getElementIcon(@IconFlags int flags) { RowIcon baseIcon = ElementPresentationUtil.createLayeredIcon(JetgroovyIcons.Groovy.Method, this, false); return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightField.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightField.java index 2ce56128a061..204f4ada7d0b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightField.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightField.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -21,6 +21,9 @@ import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiType; import com.intellij.psi.impl.ResolveScopeManager; import com.intellij.psi.search.SearchScope; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -42,11 +45,6 @@ import java.util.Map; */ public class GrLightField extends GrLightVariable implements GrField { - protected GrAccessorMethod mySetter; - protected GrAccessorMethod[] myGetters; - - protected boolean mySetterInitialized = false; - private final PsiClass myContainingClass; public GrLightField(@NotNull PsiClass containingClass, @@ -96,24 +94,27 @@ public class GrLightField extends GrLightVariable implements GrField { return PsiUtil.isProperty(this); } + @Nullable @Override public GrAccessorMethod getSetter() { - if (mySetterInitialized) return mySetter; - - mySetter = GrAccessorMethodImpl.createSetterMethod(this); - mySetterInitialized = true; - - return mySetter; + return CachedValuesManager.getCachedValue(this, new CachedValueProvider<GrAccessorMethod>() { + @Nullable + @Override + public Result<GrAccessorMethod> compute() { + return Result.create(GrAccessorMethodImpl.createSetterMethod(GrLightField.this), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }); } - @NotNull @Override public GrAccessorMethod[] getGetters() { - if (myGetters == null) { - myGetters = GrAccessorMethodImpl.createGetterMethods(this); - } - - return myGetters; + return CachedValuesManager.getCachedValue(this, new CachedValueProvider<GrAccessorMethod[]>() { + @Nullable + @Override + public Result<GrAccessorMethod[]> compute() { + return Result.create(GrAccessorMethodImpl.createGetterMethods(GrLightField.this), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }); } @NotNull @@ -123,13 +124,6 @@ public class GrLightField extends GrLightVariable implements GrField { } @Override - public void clearCaches() { - mySetterInitialized = false; - mySetter = null; - myGetters = null; - } - - @Override public void setInitializerGroovy(GrExpression initializer) { throw new IncorrectOperationException("cannot set initializer to light field!"); } @@ -178,7 +172,6 @@ public class GrLightField extends GrLightVariable implements GrField { @Override public PsiElement setName(@NotNull String name) throws IncorrectOperationException { PsiElement res = super.setName(name); - clearCaches(); return res; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrScriptField.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrScriptField.java index 42f9a912cad7..86f5bdb0e6bf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrScriptField.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrScriptField.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. @@ -23,6 +23,7 @@ import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; @@ -45,10 +46,6 @@ public class GrScriptField extends GrLightField { private GrScriptField(@NotNull GrVariable original, @NotNull GroovyScriptClass scriptClass) { super(scriptClass, original.getName(), original.getType(), original); - mySetterInitialized = true; - mySetter = null; - myGetters = GrAccessorMethod.EMPTY_ARRAY; - final GrLightModifierList modifierList = getModifierList(); for (@PsiModifier.ModifierConstant String modifier : PsiModifier.MODIFIERS) { if (original.hasModifierProperty(modifier)) { @@ -65,6 +62,17 @@ public class GrScriptField extends GrLightField { } } + @Nullable + @Override + public GrAccessorMethod getSetter() { + return null; + } + + @NotNull + @Override + public GrAccessorMethod[] getGetters() { + return GrAccessorMethod.EMPTY_ARRAY; + } @NotNull public static GrScriptField getScriptField(@NotNull final GrVariable original) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GroovyScriptClass.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GroovyScriptClass.java index 92a013c7d069..5108e852e11e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GroovyScriptClass.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GroovyScriptClass.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. @@ -158,7 +158,9 @@ public class GroovyScriptClass extends LightElement implements PsiClass, Synthet @NotNull public PsiClassType[] getExtendsListTypes() { final PsiClassType superClassFromDSL = GroovyDslFileIndex.pocessScriptSuperClasses(myFile); - return new PsiClassType[]{ superClassFromDSL != null ? superClassFromDSL : TypesUtil.createTypeByFQClassName(GroovyCommonClassNames.GROOVY_LANG_SCRIPT, this)}; + PsiClassType superClass = superClassFromDSL != null ? superClassFromDSL + : TypesUtil.createTypeByFQClassName(GroovyCommonClassNames.GROOVY_LANG_SCRIPT, this); + return new PsiClassType[]{superClass}; } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index aa7ca4cd1f68..12e6e2cb13a9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -91,10 +91,11 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl<GrCodeRef @Override protected GrCodeReferenceElement bindWithQualifiedRef(@NotNull String qName) { - final GrTypeArgumentList list = getTypeArgumentList(); - final String typeArgs = (list != null) ? list.getText() : ""; - final String text = qName + typeArgs; - final GrCodeReferenceElement qualifiedRef = GroovyPsiElementFactory.getInstance(getProject()).createTypeOrPackageReference(text); + final GrCodeReferenceElement qualifiedRef = GroovyPsiElementFactory.getInstance(getProject()).createTypeOrPackageReference(qName); + final PsiElement list = getTypeArgumentList(); + if (list != null) { + qualifiedRef.getNode().addChild(list.copy().getNode()); + } getNode().getTreeParent().replaceChild(getNode(), qualifiedRef.getNode()); return qualifiedRef; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java index 165b5f72bcc3..4607533ce644 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java @@ -29,7 +29,7 @@ import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesPr import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import java.util.Iterator; -import java.util.Set; +import java.util.List; /** * @author Max Medvedev @@ -39,14 +39,14 @@ public class ClosureAsAnonymousParameterEnhancer extends AbstractClosureParamete @Override protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { - Set<PsiType> expectedTypes; + List<PsiType> expectedTypes; if (closure.getParent() instanceof GrSafeCastExpression) { GrSafeCastExpression safeCastExpression = (GrSafeCastExpression)closure.getParent(); GrTypeElement typeElement = safeCastExpression.getCastTypeElement(); if (typeElement != null) { PsiType castType = typeElement.getType(); - expectedTypes = ContainerUtil.newHashSet(GroovyExpectedTypesProvider.getDefaultExpectedTypes(safeCastExpression)); + expectedTypes = ContainerUtil.newArrayList(GroovyExpectedTypesProvider.getDefaultExpectedTypes(safeCastExpression)); for (Iterator<PsiType> iterator = expectedTypes.iterator(); iterator.hasNext(); ) { if (!TypesUtil.isAssignable(iterator.next(), castType, closure)) { iterator.remove(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java index 2e88f33faa8d..3bea053115a0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java @@ -16,11 +16,9 @@ package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.hash.HashMap; import com.intellij.util.containers.hash.HashSet; @@ -37,7 +35,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGd import org.jetbrains.plugins.groovy.lang.psi.impl.GrRangeType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -133,17 +130,10 @@ public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer { return null; } - PsiType fromSam = inferParameterTypeFromSAM((GrMethodCall)parent, closure, index); - if (fromSam != null) { - return fromSam; - } - String methodName = findMethodName((GrMethodCall)parent); GrExpression expression = ((GrMethodCall)parent).getInvokedExpression(); if (!(expression instanceof GrReferenceExpression)) return null; -// final PsiElement resolved = ((GrReferenceExpression)expression).resolve(); -// if (!(resolved instanceof GrGdkMethod)) return null; GrExpression qualifier = ((GrReferenceExpression)expression).getQualifierExpression(); if (qualifier == null) return null; @@ -265,42 +255,6 @@ public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer { } @Nullable - private static PsiType inferParameterTypeFromSAM(@NotNull GrMethodCall methodCall, @NotNull GrClosableBlock closure, int index) { - if (!ClosureToSamConverter.isSamConversionAllowed(methodCall)) return null; - - GroovyResolveResult resolveResult = methodCall.advancedResolve(); - PsiElement resolved = resolveResult.getElement(); - - if (!(resolved instanceof PsiMethod)) return null; - - - - Map<GrExpression,Pair<PsiParameter,PsiType>> map = GrClosureSignatureUtil.mapArgumentsToParameters(resolveResult, methodCall, false, true, - methodCall.getNamedArguments(), - methodCall.getExpressionArguments(), - methodCall.getClosureArguments()); - if (map == null) return null; - - Pair<PsiParameter, PsiType> samParameter = map.get(closure); - assert samParameter != null; - - PsiType samTypeSubstituted = samParameter.getSecond(); - if (!(samTypeSubstituted instanceof PsiClassType)) return null; - - MethodSignature samSignature = ClosureToSamConverter.findSAMSignature(samTypeSubstituted); - if (samSignature == null) return null; - - PsiType[] parameterTypes = samSignature.getParameterTypes(); - - if (index >= parameterTypes.length) { - return null; - } - - return parameterTypes[index]; - } - - - @Nullable private static PsiType getEntryForMap(@Nullable PsiType map, @NotNull final Project project, @NotNull final GlobalSearchScope scope) { PsiType key = PsiUtil.substituteTypeParameter(map, CommonClassNames.JAVA_UTIL_MAP, 0, true); PsiType value = PsiUtil.substituteTypeParameter(map, CommonClassNames.JAVA_UTIL_MAP, 1, true); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParamsEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParamsEnhancer.java new file mode 100644 index 000000000000..d71763079839 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParamsEnhancer.java @@ -0,0 +1,144 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 27/02/14 + */ +public class ClosureParamsEnhancer extends AbstractClosureParameterEnhancer { + + @Nullable + @Override + protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { + if (!GroovyConfigUtils.getInstance().isVersionAtLeast(closure, GroovyConfigUtils.GROOVY2_3)) return null; + + final GrParameter[] parameters = closure.getAllParameters(); + if (containsParametersWithDeclaredType(parameters)) { + return null; + } + + List<PsiType[]> fittingSignatures = findFittingSignatures(closure); + + if (fittingSignatures.size() == 1) { + PsiType[] expectedSignature = fittingSignatures.get(0); + return expectedSignature[index]; + } + + return null; + } + + @NotNull + public static List<PsiType[]> findFittingSignatures(GrClosableBlock closure) { + + final GrParameter[] parameters = closure.getAllParameters(); + + GrCall call = findCall(closure); + if (call == null) return Collections.emptyList(); + + GroovyResolveResult resolveResult = call.advancedResolve(); + PsiElement element = resolveResult.getElement(); + + if (!(element instanceof PsiMethod)) { + return Collections.emptyList(); + } + + while (element instanceof PsiMirrorElement) { + element = ((PsiMirrorElement)element).getPrototype(); + } + + List<Pair<PsiParameter,PsiType>> params = ResolveUtil.collectExpectedParamsByArg(closure, + new GroovyResolveResult[]{resolveResult}, + call.getNamedArguments(), + call.getExpressionArguments(), + call.getClosureArguments(), closure); + if (params.isEmpty()) return Collections.emptyList(); + + Pair<PsiParameter, PsiType> pair = params.get(0); + + PsiParameter param = pair.getFirst(); + PsiModifierList modifierList = param.getModifierList(); + if (modifierList == null) return Collections.emptyList(); + + PsiAnnotation anno = modifierList.findAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_STC_CLOSURE_PARAMS); + if (anno == null) return Collections.emptyList(); + + PsiClass closureSignatureHint = GrAnnotationUtil.inferClassAttribute(anno, "value"); + if (closureSignatureHint == null) return Collections.emptyList(); + + String qnameOfClosureSignatureHint = closureSignatureHint.getQualifiedName(); + if (qnameOfClosureSignatureHint == null) return Collections.emptyList(); + + SignatureHintProcessor signatureHintProcessor = SignatureHintProcessor.getHintProcessor(qnameOfClosureSignatureHint); + if (signatureHintProcessor == null) return Collections.emptyList(); + + List<PsiType[]> expectedSignatures = signatureHintProcessor.inferExpectedSignatures((PsiMethod)element, + resolveResult.getSubstitutor(), + SignatureHintProcessor.buildOptions(anno)); + + return ContainerUtil.findAll(expectedSignatures, new Condition<PsiType[]>() { + @Override + public boolean value(PsiType[] types) { + return types.length == parameters.length; + } + }); + } + + private static boolean containsParametersWithDeclaredType(GrParameter[] parameters) { + return ContainerUtil.find(parameters, new Condition<GrParameter>() { + @Override + public boolean value(GrParameter parameter) { + return parameter.getDeclaredType() != null; + } + }) != null; + } + + @Nullable + private static GrCall findCall(@NotNull GrClosableBlock closure) { + PsiElement parent = closure.getParent(); + if (parent instanceof GrCall && ArrayUtil.contains(closure, ((GrCall)parent).getClosureArguments())) { + return (GrCall)parent; + } + + if (parent instanceof GrArgumentList) { + PsiElement pparent = parent.getParent(); + if (pparent instanceof GrCall) { + return (GrCall)pparent; + } + } + + return null; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FirstParamHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FirstParamHintProcessor.java new file mode 100644 index 000000000000..7fdc10341c41 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FirstParamHintProcessor.java @@ -0,0 +1,77 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.PsiArrayType; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class FirstParamHintProcessor extends ParamHintProcessor { + public FirstParamHintProcessor() { + super("groovy.transform.stc.FirstParam", 0, -1); + } + + public static class FirstGeneric extends ParamHintProcessor { + public FirstGeneric() { + super("groovy.transform.stc.FirstParam.FirstGenericType", 0, 0); + } + } + + public static class SecondGeneric extends ParamHintProcessor { + public SecondGeneric() { + super("groovy.transform.stc.FirstParam.SecondGenericType", 0, 1); + } + } + + public static class ThirdGeneric extends ParamHintProcessor { + public ThirdGeneric() { + super("groovy.transform.stc.FirstParam.ThirdGenericType", 0, 2); + } + } + + public static class Component extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.FirstParam.Component"; + } + + @NotNull + @Override + public List<PsiType[]> inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + List<PsiType[]> signatures = new FirstParamHintProcessor().inferExpectedSignatures(method, substitutor, options); + if (signatures.size() == 1) { + PsiType[] signature = signatures.get(0); + if (signature.length == 1) { + PsiType type = signature[0]; + if (type instanceof PsiArrayType) { + return produceResult(((PsiArrayType)type).getComponentType()); + } + } + } + return Collections.emptyList(); + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsHintProcessor.java new file mode 100644 index 000000000000..d1c666fda47b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsHintProcessor.java @@ -0,0 +1,57 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.codeInsight.generation.OverrideImplementExploreUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignature; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class FromAbstractTypeMethodsHintProcessor extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.FromAbstractTypeMethods"; + } + + @NotNull + @Override + public List<PsiType[]> inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + if (options.length != 1) return Collections.emptyList(); + + String qname = options[0]; + PsiClass aClass = JavaPsiFacade.getInstance(method.getProject()).findClass(qname, method.getResolveScope()); + if (aClass == null) return Collections.emptyList(); + + Collection<MethodSignature> abstractSignatures = OverrideImplementExploreUtil.getMethodSignaturesToImplement(aClass); + return ContainerUtil.map(abstractSignatures, new Function<MethodSignature, PsiType[]>() { + @Override + public PsiType[] fun(MethodSignature signature) { + return signature.getParameterTypes(); + } + }); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java new file mode 100644 index 000000000000..6ca36c5bb70f --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java @@ -0,0 +1,64 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class FromStringHintProcessor extends SignatureHintProcessor { + + @Override + public String getHintName() { + return "groovy.transform.stc.FromString"; + } + + @NotNull + @Override + public List<PsiType[]> inferExpectedSignatures(@NotNull final PsiMethod method, + @NotNull final PsiSubstitutor substitutor, + @NotNull String[] options) { + return ContainerUtil.map(options, new Function<String, PsiType[]>() { + @Override + public PsiType[] fun(String value) { + String[] params = value.split(","); + return ContainerUtil.map(params, new Function<String, PsiType>() { + @Override + public PsiType fun(String param) { + try { + PsiType original = JavaPsiFacade.getElementFactory(method.getProject()).createTypeFromText(param, method); + return substitutor.substitute(original); + } + catch (IncorrectOperationException e) { + //do nothing. Just don't throw an exception + } + return PsiType.NULL; + } + }, new PsiType[params.length]); + } + }); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/MapEntryOrKeyValueHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/MapEntryOrKeyValueHintProcessor.java new file mode 100644 index 000000000000..799d02a50dd0 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/MapEntryOrKeyValueHintProcessor.java @@ -0,0 +1,136 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtilRt; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class MapEntryOrKeyValueHintProcessor extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.MapEntryOrKeyValue"; + } + + @NotNull + @Override + public List<PsiType[]> inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + int argNum = extractArgNum(options); + boolean index = extractIndex(options); + + PsiParameter[] parameters = method.getParameterList().getParameters(); + + if (argNum >= parameters.length) return ContainerUtil.emptyList(); + + PsiParameter parameter = parameters[argNum]; + PsiType type = parameter.getType(); + PsiType substituted = substitutor.substitute(type); + + if (!InheritanceUtil.isInheritor(substituted, CommonClassNames.JAVA_UTIL_MAP)) return ContainerUtil.emptyList(); + + PsiType key = PsiUtil.substituteTypeParameter(substituted, CommonClassNames.JAVA_UTIL_MAP, 0, true); + PsiType value = PsiUtil.substituteTypeParameter(substituted, CommonClassNames.JAVA_UTIL_MAP, 1, true); + + PsiClass mapEntry = JavaPsiFacade.getInstance(method.getProject()).findClass(CommonClassNames.JAVA_UTIL_MAP_ENTRY, method.getResolveScope()); + if (mapEntry == null) return ContainerUtil.emptyList(); + + PsiClassType mapEntryType = JavaPsiFacade.getElementFactory(method.getProject()).createType(mapEntry, key, value); + + PsiType[] keyValueSignature = index ? new PsiType[]{key, value, PsiType.INT} : new PsiType[]{key, value}; + PsiType[] mapEntrySignature = index ? new PsiType[]{mapEntryType, PsiType.INT} : new PsiType[]{mapEntryType}; + + return ContainerUtil.newArrayList(keyValueSignature, mapEntrySignature); + } + + private static int extractArgNum(String[] options) { + + + for (String value : options) { + Integer parsedValue = parseArgNum(value); + if (parsedValue != null) { + return parsedValue; + } + } + + if (options.length == 1) { + return StringUtilRt.parseInt(options[0], 0); + } + + return 0; + } + + private static boolean extractIndex(String[] options) { + for (String value : options) { + Boolean parsedValue = parseIndex(value); + if (parsedValue != null) { + return parsedValue; + } + } + + if (options.length == 1) { + return StringUtilRt.parseBoolean(options[0], false); + } + + return false; + } + + private static Boolean parseIndex(String value) { + Pair<String, String> pair = parseValue(value); + if (pair == null) return null; + + Boolean parsedValue = StringUtilRt.parseBoolean(pair.getSecond(), false); + if ("index".equals(pair.getFirst())) { + return parsedValue; + } + + return null; + } + + private static Integer parseArgNum(String value) { + Pair<String, String> pair = parseValue(value); + if (pair == null) return null; + + Integer parsedValue = StringUtilRt.parseInt(pair.getSecond(), 0); + if ("argNum".equals(pair.getFirst())) { + return parsedValue; + } + + return null; + } + + @Nullable + private static Pair<String, String> parseValue(String value) { + String[] splitted = value.split("="); + + if (splitted.length == 2) { + return Pair.create(splitted[0].trim(), splitted[1].trim()); + } + + return null; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ParamHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ParamHintProcessor.java new file mode 100644 index 000000000000..3c9ac95506b5 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ParamHintProcessor.java @@ -0,0 +1,84 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.*; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.ContainerUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public abstract class ParamHintProcessor extends SignatureHintProcessor { + private final int myParam; + private final int myGeneric; + private final String myHint; + + public ParamHintProcessor(String hint, int param, int generic) { + myHint = hint; + myParam = param; + myGeneric = generic; + } + + @Override + public String getHintName() { + return myHint; + } + + @NotNull + @Override + public List<PsiType[]> inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + PsiParameter[] parameters = method.getParameterList().getParameters(); + if (myParam < parameters.length) { + PsiParameter parameter = parameters[myParam]; + PsiType originalType = parameter.getType(); + + PsiType substituted = substitutor.substitute(originalType); + + if (myGeneric == -1) { + return produceResult(substituted); + } + else { + if (substituted instanceof PsiClassType) { + PsiType[] typeParameters = ((PsiClassType)substituted).getParameters(); + if (myGeneric < typeParameters.length) { + return produceResult(typeParameters[myGeneric]); + } + //if (substituted.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + // return produceResult(TypesUtil.createType(CommonClassNames.JAVA_LANG_CHARACTER, method)); + //} + } + } + } + return ContainerUtilRt.emptyList(); + } + + @NotNull + protected static ArrayList<PsiType[]> produceResult(@Nullable PsiType type) { + PsiType notNull = type != null ? type : PsiType.NULL; + PsiType[] signature = {notNull}; + ArrayList<PsiType[]> result = ContainerUtil.newArrayList(); + result.add(signature); + return result; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SecondParamHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SecondParamHintProcessor.java new file mode 100644 index 000000000000..fbfa821327d2 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SecondParamHintProcessor.java @@ -0,0 +1,78 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.PsiArrayType; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class SecondParamHintProcessor extends ParamHintProcessor { + public SecondParamHintProcessor() { + super("groovy.transform.stc.SecondParam", 1, -1); + } + + public static class FirstGeneric extends ParamHintProcessor { + public FirstGeneric() { + super("groovy.transform.stc.SecondParam.FirstGenericType", 1, 0); + } + } + + public static class SecondGeneric extends ParamHintProcessor { + public SecondGeneric() { + super("groovy.transform.stc.SecondParam.SecondGenericType", 1, 1); + } + } + + public static class ThirdGeneric extends ParamHintProcessor { + public ThirdGeneric() { + super("groovy.transform.stc.SecondParam.ThirdGenericType", 1, 2); + } + } + + public static class Component extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.SecondParam.Component"; + } + + @NotNull + @Override + public List<PsiType[]> inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + List<PsiType[]> signatures = new SecondParamHintProcessor().inferExpectedSignatures(method, substitutor, options); + if (signatures.size() == 1) { + PsiType[] signature = signatures.get(0); + if (signature.length == 1) { + PsiType type = signature[0]; + if (type instanceof PsiArrayType) { + return produceResult(((PsiArrayType)type).getComponentType()); + } + } + } + return Collections.emptyList(); + } + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SignatureHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SignatureHintProcessor.java new file mode 100644 index 000000000000..44c8f2ac5094 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SignatureHintProcessor.java @@ -0,0 +1,77 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public abstract class SignatureHintProcessor { + private static final ExtensionPointName<SignatureHintProcessor> EP_NAME = ExtensionPointName.create("org.intellij.groovy.signatureHintProcessor"); + + static String[] buildOptions(PsiAnnotation anno) { + PsiAnnotationMemberValue options = anno.findAttributeValue("options"); + if (options instanceof PsiLiteral) { + Object value = ((PsiLiteral)options).getValue(); + if (value instanceof String) { + return new String[]{(String)value}; + } + } + else if (options instanceof PsiArrayInitializerMemberValue) { + PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)options).getInitializers(); + ArrayList<String> result = ContainerUtil.newArrayList(); + for (PsiAnnotationMemberValue initializer : initializers) { + if (initializer instanceof PsiLiteral) { + Object value = ((PsiLiteral)initializer).getValue(); + if (value instanceof String) { + result.add((String)value); + } + } + } + + return ArrayUtil.toStringArray(result); + } + + return ArrayUtil.EMPTY_STRING_ARRAY; + } + + public abstract String getHintName(); + + @NotNull + public abstract List<PsiType[]> inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options); + + @Nullable + public static SignatureHintProcessor getHintProcessor(@NotNull String hint) { + for (SignatureHintProcessor processor : EP_NAME.getExtensions()) { + if (hint.equals(processor.getHintName())) { + return processor; + } + } + + return null; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SimpleTypeHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SimpleTypeHintProcessor.java new file mode 100644 index 000000000000..dc5fafe40715 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/SimpleTypeHintProcessor.java @@ -0,0 +1,58 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import org.codehaus.groovy.runtime.DefaultGroovyMethods; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class SimpleTypeHintProcessor extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.SimpleType"; + } + + @NotNull + @Override + public List<PsiType[]> inferExpectedSignatures(@NotNull final PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + return Collections.singletonList(ContainerUtil.map(options, new Function<String, PsiType>() { + @Override + public PsiType fun(String value) { + try { + PsiType type = JavaPsiFacade.getElementFactory(method.getProject()).createTypeFromText(value, method); + return DefaultGroovyMethods.asBoolean(type) ? type : PsiType.NULL; + } + catch (IncorrectOperationException e) { + return PsiType.NULL; + } + } + }, new PsiType[options.length])); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ThirdParamHintProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ThirdParamHintProcessor.java new file mode 100644 index 000000000000..89d935593b1a --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ThirdParamHintProcessor.java @@ -0,0 +1,78 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.PsiArrayType; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Created by Max Medvedev on 28/02/14 + */ +public class ThirdParamHintProcessor extends ParamHintProcessor { + public ThirdParamHintProcessor() { + super("groovy.transform.stc.ThirdParam", 2, -1); + } + + public static class FirstGeneric extends ParamHintProcessor { + public FirstGeneric() { + super("groovy.transform.stc.ThirdParam.FirstGenericType", 2, 0); + } + } + + public static class SecondGeneric extends ParamHintProcessor { + public SecondGeneric() { + super("groovy.transform.stc.ThirdParam.SecondGenericType", 2, 1); + } + } + + public static class ThirdGeneric extends ParamHintProcessor { + public ThirdGeneric() { + super("groovy.transform.stc.ThirdParam.ThirdGenericType", 2, 2); + } + } + + public static class Component extends SignatureHintProcessor { + @Override + public String getHintName() { + return "groovy.transform.stc.ThirdParam.Component"; + } + + @NotNull + @Override + public List<PsiType[]> inferExpectedSignatures(@NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor, + @NotNull String[] options) { + List<PsiType[]> signatures = new ThirdParamHintProcessor().inferExpectedSignatures(method, substitutor, options); + if (signatures.size() == 1) { + PsiType[] signature = signatures.get(0); + if (signature.length == 1) { + PsiType type = signature[0]; + if (type instanceof PsiArrayType) { + return produceResult(((PsiArrayType)type).getComponentType()); + } + } + } + return Collections.emptyList(); + } + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index dc08b531786e..75496889f9a4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.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. @@ -617,7 +617,7 @@ public class GrClassImplUtil { private static boolean shouldImplementDelegatedInterfaces(PsiAnnotation delegate) { final Boolean result = GrAnnotationUtil.inferBooleanAttribute(delegate, "interfaces"); - return result != null ? result.booleanValue() : true; + return result == null || result.booleanValue(); } public static void addExpandingReflectedMethods(List<PsiMethod> result, PsiMethod method) { @@ -631,12 +631,12 @@ public class GrClassImplUtil { result.add(method); } - public static void collectMethodsFromBody(@NotNull GrTypeDefinitionBody body, List<PsiMethod> result) { - for (GrMethod method : body.getMethods()) { + public static void collectMethodsFromBody(@NotNull GrTypeDefinition definition, List<PsiMethod> result) { + for (GrMethod method : definition.getCodeMethods()) { addExpandingReflectedMethods(result, method); } - for (GrField field : body.getFields()) { + for (GrField field : definition.getFields()) { if (!field.isProperty()) continue; ContainerUtil.addAll(result, field.getGetters()); ContainerUtil.addIfNotNull(result, field.getSetter()); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java index cfd5a265f6c8..0cf18709c585 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.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. @@ -68,7 +68,7 @@ public final class GroovyCommonClassNames { @NonNls public static final String GROOVY_LANG_DELEGATES_TO = "groovy.lang.DelegatesTo"; @NonNls public static final String GROOVY_LANG_DELEGATES_TO_TARGET = "groovy.lang.DelegatesTo.Target"; @NonNls public static final String GROOVY_TRANSFORM_COMPILE_DYNAMIC = "groovy.transform.CompileDynamic"; - + @NonNls public static final String GROOVY_TRANSFORM_STC_CLOSURE_PARAMS = "groovy.transform.stc.ClosureParams"; public static final Set<String> GROOVY_EXTENSION_CLASSES = Collections.unmodifiableSet(ContainerUtil.newLinkedHashSet( "org.codehaus.groovy.runtime.DateGroovyMethods", diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 98bd1d918f5c..ad16d8d71297 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -48,6 +48,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; @@ -916,6 +917,33 @@ public class ResolveUtil { } } + @NotNull + public static List<Pair<PsiParameter, PsiType>> collectExpectedParamsByArg(@NotNull PsiElement place, + @NotNull GroovyResolveResult[] variants, + @NotNull GrNamedArgument[] namedArguments, + @NotNull GrExpression[] expressionArguments, + @NotNull GrClosableBlock[] closureArguments, + @NotNull GrExpression arg) { + List<Pair<PsiParameter, PsiType>> expectedParams = ContainerUtil.newArrayList(); + + for (GroovyResolveResult variant : variants) { + final Map<GrExpression, Pair<PsiParameter, PsiType>> map = GrClosureSignatureUtil.mapArgumentsToParameters( + variant, place, true, true, namedArguments, expressionArguments, closureArguments + ); + + if (map != null) { + final Pair<PsiParameter, PsiType> pair = map.get(arg); + ContainerUtil.addIfNotNull(expectedParams, pair); + } + } + return expectedParams; + } + + @NotNull + public static List<Pair<PsiParameter, PsiType>> collectExpectedParamsByArg(@NotNull GrCall call, @NotNull GrExpression arg) { + return collectExpectedParamsByArg(arg, call.getCallVariants(arg), call.getNamedArguments(), call.getExpressionArguments(), call.getClosureArguments(), arg); + } + private static class DuplicateVariablesProcessor extends PropertyResolverProcessor { private boolean myBorderPassed; private final boolean myHasVisibilityModifier; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java index 2aa286e972bc..edb458e2d94c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java @@ -37,7 +37,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; @@ -117,10 +116,7 @@ public class DelegatedMethodsContributor extends AstTransformContributor { final List<PsiMethod> methods; if (clazz instanceof GrTypeDefinition) { methods = new ArrayList<PsiMethod>(); - final GrTypeDefinitionBody body = ((GrTypeDefinition)clazz).getBody(); - if (body != null) { - GrClassImplUtil.collectMethodsFromBody(body, methods); - } + GrClassImplUtil.collectMethodsFromBody((GrTypeDefinition)clazz, methods); } else { methods = Arrays.asList(clazz.getMethods()); @@ -247,10 +243,7 @@ public class DelegatedMethodsContributor extends AstTransformContributor { final List<PsiMethod> methods; if (currentClass instanceof GrTypeDefinition) { methods = new ArrayList<PsiMethod>(); - final GrTypeDefinitionBody body = ((GrTypeDefinition)currentClass).getBody(); - if (body != null) { - GrClassImplUtil.collectMethodsFromBody(body, methods); - } + GrClassImplUtil.collectMethodsFromBody((GrTypeDefinition)currentClass, methods); } else { methods = Arrays.asList(currentClass.getMethods()); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java index 10e93acc5a22..e78cc0800d24 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java @@ -730,7 +730,7 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting return candidate; } - public static void assertStatement(@NotNull PsiElement anchor, @NotNull PsiElement scope) { + public static void assertStatement(@Nullable PsiElement anchor, @NotNull PsiElement scope) { if (!(anchor instanceof GrStatement)) { LogMessageEx.error(LOG, "cannot find anchor for variable", scope.getText()); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterHandler.java index 9f1a9848476f..165f0f58e669 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterHandler.java @@ -188,7 +188,10 @@ public class GrIntroduceParameterHandler implements RefactoringActionHandler, Me private static boolean isInplace(@NotNull IntroduceParameterInfo info, @NotNull Editor editor) { - return findExpr(info) != null && GrIntroduceHandlerBase.isInplace(editor, info.getContext()); + return findExpr(info) != null && + info.getToReplaceIn() instanceof GrMethod && + info.getToSearchFor() instanceof PsiMethod && + GrIntroduceHandlerBase.isInplace(editor, info.getContext()); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/dynamicMembers/GrDynamicPropertyImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/dynamicMembers/GrDynamicPropertyImpl.java index 1521684d1d9c..ecd79e61acc4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/dynamicMembers/GrDynamicPropertyImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/dynamicMembers/GrDynamicPropertyImpl.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. @@ -202,11 +202,6 @@ public class GrDynamicPropertyImpl extends LightElement implements GrField { } @Override - public void clearCaches() { - myField.clearCaches(); - } - - @Override public void setInitializerGroovy(GrExpression initializer) { throw new IncorrectOperationException("cannot set initializer to dynamic property!"); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/FastGroovyTestSuite.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/FastGroovyTestSuite.java index 11597e915fe4..42404baeec57 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/FastGroovyTestSuite.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/FastGroovyTestSuite.java @@ -19,7 +19,6 @@ import com.intellij.TestAll; import com.intellij.TestCaseLoader; import junit.framework.Test; import junit.framework.TestSuite; -import org.jetbrains.plugins.groovy.compiler.GppCompilerTest; import org.jetbrains.plugins.groovy.compiler.GroovyCompilerTest; import org.jetbrains.plugins.groovy.compiler.GroovyDebuggerTest; import org.jetbrains.plugins.groovy.lang.GroovyStressPerformanceTest; @@ -46,8 +45,7 @@ public class FastGroovyTestSuite { private static boolean isSlow(Class aClass) { return aClass.equals(GroovyDebuggerTest.class) || aClass.equals(GroovyStressPerformanceTest.class) || - aClass.getName().startsWith(GroovyCompilerTest.class.getName()) || - aClass.getName().startsWith(GppCompilerTest.class.getName()); + aClass.getName().startsWith(GroovyCompilerTest.class.getName()); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GppCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GppCompilerTest.groovy deleted file mode 100644 index 316de960091c..000000000000 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GppCompilerTest.groovy +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.plugins.groovy.compiler - -import com.intellij.compiler.CompilerConfiguration -import com.intellij.compiler.CompilerConfigurationImpl -import com.intellij.compiler.server.BuildManager -import com.intellij.openapi.util.io.FileUtil -import com.intellij.openapi.vfs.VfsUtil -import com.intellij.testFramework.PsiTestUtil -import org.jetbrains.plugins.groovy.util.TestUtils -/** - * @author peter - */ -public abstract class GppCompilerTest extends GroovyCompilerTestCase { - String[] oldPatterns - - @Override protected void setUp() { - super.setUp(); - PsiTestUtil.addLibrary myFixture.module, "gpp", TestUtils.absoluteTestDataPath + "/realGroovypp/", "groovy-all-1.8.2.jar", "groovypp-all-0.9.0_1.8.2.jar" - CompilerConfigurationImpl conf = CompilerConfiguration.getInstance(project) - oldPatterns = conf.resourceFilePatterns - conf.addResourceFilePattern("!*.gpp") - } - - @Override - protected void tearDown() { - CompilerConfigurationImpl conf = CompilerConfiguration.getInstance(project) - conf.removeResourceFilePatterns() - oldPatterns.each { conf.addResourceFilePattern(it) } - super.tearDown() - } - - public void testRecompileDependentGroovyClasses() throws Exception { - def a = myFixture.addFileToProject("A.gpp", """ -class A { - void foo() { - print "239" - } -} -""") - myFixture.addFileToProject("b.gpp", """ -new A().foo() -""") - assertEmpty make() - assertOutput "b", "239" - - VfsUtil.saveText a.virtualFile, """ -class A { - def foo() { - print "239" - } -} -""" - - assertEmpty make() - assertOutput "b", "239" - } - - public void testRecompileDependentJavaClasses() throws Exception { - def a = myFixture.addFileToProject("A.gpp", """ -class A { - void foo() { - print "239" - } -} -""") - myFixture.addFileToProject("B.java", """ -public class B { - public static void main(String[] args) { - new A().foo(); - } -} -""") - assertEmpty make() - assertOutput "B", "239" - - VfsUtil.saveText a.virtualFile, """ -class A { - def foo() { - print "239" - } -} -""" - - assertEmpty make() - assertOutput "B", "239" - } - - public static class IdeaModeTest extends GppCompilerTest { - @Override - protected boolean useJps() { false } - } - - public static class JpsModeTest extends GppCompilerTest { - @Override - protected boolean useJps() { true } - - @Override - void testRecompileDependentJavaClasses() { - super.testRecompileDependentJavaClasses() - } - - @Override - void testRecompileDependentGroovyClasses() { - super.testRecompileDependentGroovyClasses() - } - - @Override - protected void tearDown() { - File systemRoot = BuildManager.getInstance().getBuildSystemDirectory() - try { - super.tearDown() - } - finally { - FileUtil.delete(systemRoot); - } - } - } - - -} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy index da3963e9b7e1..9be76d2096db 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy @@ -17,9 +17,9 @@ package org.jetbrains.plugins.groovy.compiler import com.intellij.compiler.CompilerConfiguration import com.intellij.compiler.CompilerConfigurationImpl +import com.intellij.compiler.impl.TranslatingCompilerFilesMonitor import com.intellij.compiler.server.BuildManager import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.PathManager import com.intellij.openapi.compiler.CompilerMessage import com.intellij.openapi.compiler.CompilerMessageCategory import com.intellij.openapi.compiler.options.ExcludeEntryDescription @@ -41,6 +41,12 @@ public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { addGroovyLibrary(myModule); } + @Override + protected void tearDown() throws Exception { + TranslatingCompilerFilesMonitor.ourDebugMode = false + super.tearDown() + } + public void testPlainGroovy() throws Throwable { myFixture.addFileToProject("A.groovy", "println '239'"); assertEmpty(make()); @@ -128,6 +134,8 @@ public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { } public void testTransitiveJavaDependencyThroughGroovy() throws Throwable { + TranslatingCompilerFilesMonitor.ourDebugMode = true + myFixture.addClass("public class IFoo { void foo() {} }").getContainingFile().getVirtualFile(); myFixture.addFileToProject("Foo.groovy", "class Foo {\n" + " static IFoo f\n" + @@ -208,7 +216,7 @@ public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { @Override void runBare() { - new File(PathManager.systemPath, "compile-server/server.log").delete() + new File(TestLoggerFactory.testLogDir, "../log/build-log/build.log").delete() super.runBare() } @@ -231,7 +239,7 @@ public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { def logText = ideaLog.text println(logText.size() < limit ? logText : logText.substring(logText.size() - limit)) } - def makeLog = new File(PathManager.systemPath, "compile-server/server.log") + def makeLog = new File(TestLoggerFactory.testLogDir, "../log/build-log/build.log") if (makeLog.exists()) { println "\n\nServer Log:" println makeLog.text @@ -725,11 +733,11 @@ public class Main { ApplicationManager.application.runWriteAction { msg.virtualFile.delete(this) } def messages = make() - assert messages + assert messages def error = messages.find { it.message.contains('InvalidType') } assert error?.virtualFile assert groovyFile.classes[0] == GroovycStubGenerator.findClassByStub(project, error.virtualFile) - + } public void "test ignore groovy internal non-existent interface helper inner class"() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/Gr2_3HighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/Gr2_3HighlightingTest.groovy new file mode 100644 index 000000000000..273eb8feca63 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/Gr2_3HighlightingTest.groovy @@ -0,0 +1,275 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.highlighting + +import com.intellij.codeInspection.InspectionProfileEntry +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection +import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection + +/** + * Created by Max Medvedev on 27/02/14 + */ +class Gr2_3HighlightingTest extends GrHighlightingTestBase { + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return GroovyLightProjectDescriptor.GROOVY_2_3 + } + + @Override + InspectionProfileEntry[] getCustomInspections() { + [new GroovyAssignabilityCheckInspection(), new GrUnresolvedAccessInspection()] + } + + void assertScript(String text) { + testHighlighting("import groovy.transform.CompileStatic\nimport groovy.transform.stc.ClosureParams\n" + text) + } + + void shouldFailWithMessages(String text) { + assertScript(text) + } + + void testInferenceOnNonExtensionMethod() { + assertScript ''' +import groovy.transform.stc.FirstParam + +public <T> T foo(T arg, @ClosureParams(FirstParam) Closure c) { c.call(arg) } + +@CompileStatic +def test() { + assert foo('a') { it.toUpperCase() } == 'A' +} +''' + } + + void testFromStringWithSimpleType() { + assertScript ''' +import groovy.transform.stc.FromString + +void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') } + +@CompileStatic +def test() { + foo { String str -> println str.toUpperCase()} +} +''' + + shouldFailWithMessages ''' +import groovy.transform.stc.FromString + +void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') } + +@CompileStatic +def test() { + foo { <error descr="Expected String">Date</error> str -> println str} +} +''' + } + + void testFromStringWithGenericType() { + assertScript ''' +import groovy.transform.stc.FromString + +void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) } + +@CompileStatic +def test() { + foo { List<String> str -> str.each { println it.toUpperCase() } } +} +''' + + shouldFailWithMessages ''' +import groovy.transform.stc.FromString + +void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) } + +@CompileStatic +def test() { + foo { <error descr="Expected List<String>">List<Date></error> d -> d.each { println it } } +} +''' + } + + void testFromStringWithDirectGenericPlaceholder() { + + assertScript ''' +import groovy.transform.stc.FromString + +public <T> void foo(T t, @ClosureParams(value=FromString,options="T") Closure cl) { cl.call(t) } + +@CompileStatic +def test() { + foo('hey') { println it.toUpperCase() } +} +''' + + } + + void testFromStringWithGenericPlaceholder() { + assertScript ''' +import groovy.transform.stc.FromString + +public <T> void foo(T t, @ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call([t,t]) } + +@CompileStatic +def test() { + foo('hey') { List<String> str -> str.each { println it.toUpperCase() } } +} +''' + + } + + void testFromStringWithGenericPlaceholderFromClass() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo<T> { + public void foo(@ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call(['hey','ya']) } +} + +@CompileStatic +def test() { + def foo = new Foo<String>() + + foo.foo { List<String> str -> str.each { println it.toUpperCase() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenerics() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo<T,U> { + public void foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) } +} + +@CompileStatic +def test() { + def foo = new Foo<Integer,String>() + + foo.foo { List<String> str -> str.each { println it.toUpperCase() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignature() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo<T,U> { + public void foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) } +} + +@CompileStatic +def test() { + def foo = new Foo<Integer,String>() + + foo.foo { it.each { println it.toUpperCase() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQN() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo<T,U> { + public void foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { cl.call(['hey','ya']) } +} + +@CompileStatic +def test() { + def foo = new Foo<Integer,String>() + + foo.foo { it.each { println it.toUpperCase() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClass() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + void bar() { + println 'Haha!' + } +} + +class Tor<D,U> { + public void foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { cl.call([new Foo(), new Foo()]) } +} + +@CompileStatic +def test() { + def tor = new Tor<Integer,Foo>() + + tor.foo { it.each { it.bar() } } +}''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClassAndTwoArgs() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + void bar() { + println 'Haha!' + } +} + +class Tor<D,U> { + public void foo(@ClosureParams(value=FromString,options=["D,List<U>"]) Closure cl) { cl.call(3, [new Foo(), new Foo()]) } +} + +@CompileStatic +def test() { + + def tor = new Tor<Integer,Foo>() + + tor.foo { r, e -> r.times { e.each { it.bar() } } } +} +''' + } + + void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndPolymorphicSignature() { + assertScript ''' +import groovy.transform.stc.FromString + +class Foo { + void bar() { + println 'Haha!' + } +} + +class Tor<D,U> { + public void foo(@ClosureParams(value=FromString,options=["D,List<U>", "D"]) Closure cl) { + if (cl.maximumNumberOfParameters==2) { + cl.call(3, [new Foo(), new Foo()]) + } else { + cl.call(3) + } + } +} + +@CompileStatic +def test() { + def tor = new Tor<Integer,Foo>() + + tor.foo { r, e -> r.times { e.each { it.bar() } } } + tor.foo { it.times { println 'polymorphic' } } +} +''' + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy index 2b9ecad11444..246c5ca0b7f5 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy @@ -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. @@ -26,9 +26,9 @@ import org.jetbrains.plugins.groovy.codeInspection.declaration.GrMethodMayBeStat import org.jetbrains.plugins.groovy.codeInspection.exception.GroovyEmptyCatchBlockInspection import org.jetbrains.plugins.groovy.codeInspection.metrics.GroovyOverlyLongMethodInspection import org.jetbrains.plugins.groovy.codeInspection.noReturnMethod.MissingReturnInspection -import org.jetbrains.plugins.groovy.codeInspection.threading.GroovyUnconditionalWaitInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GroovyUntypedAccessInspection + /** * @author Max Medvedev */ @@ -146,29 +146,6 @@ boolean bar(def list) { ''', MissingReturnInspection) } - void testReassignedVarInClosureInspection() { - addCompileStatic() - testHighlighting("""\ -test() { - def var = "abc" - def cl = { - <warning descr="Local variable 'var' is reassigned">var</warning> = new Date() - } - cl() - var.toUpperCase() -} - -test2() { - def var = "abc" - def cl = { - <warning descr="Local variable 'var' is reassigned">var</warning> = 'cde' - } - cl() - var.toUpperCase() -} -""", GrReassignedInClosureLocalVarInspection) - } - void testPackageDefinition() { myFixture.addFileToProject('cde/bar.groovy', '//empty file') myFixture.addFileToProject('abc/foo.groovy', '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/GroovyAddImportActionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/GroovyAddImportActionTest.groovy index 54543f271545..97fb5d1345dc 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/GroovyAddImportActionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/GroovyAddImportActionTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,7 @@ */ package org.jetbrains.plugins.groovy.refactoring.optimizeImports - import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase -import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection /** * @author peter */ @@ -27,20 +25,34 @@ public class GroovyAddImportActionTest extends LightCodeInsightFixtureTestCase { myFixture.addClass 'package foo; public class Log {}' myFixture.addClass 'package bar; public class Log {}' myFixture.addClass 'package bar; public class LogFactory { public static Log log(){} }' - myFixture.configureByText 'a.groovy', ''' + doTest('''\ public class Foo { Lo<caret>g l = bar.LogFactory.log(); } -''' - myFixture.enableInspections(new GrUnresolvedAccessInspection()) - - importClass() - myFixture.checkResult '''import bar.Log +''', '''\ +import bar.Log public class Foo { Lo<caret>g l = bar.LogFactory.log(); } -''' +''') + } + + void testReferenceWithErrors() { + myFixture.addClass 'package foo; public class Abc<X, Y> {}' + doTest('''\ +A<caret>bc<String, > foo = null +''', '''\ +import foo.Abc + +A<caret>bc<String, > foo = null +''') + } + + private void doTest(String before, String after) { + myFixture.configureByText 'a.groovy', before + importClass() + myFixture.checkResult after } private def importClass() { diff --git a/plugins/groovy/testdata/mockGroovyLib2.3/groovy-all-2.3.0.jar b/plugins/groovy/testdata/mockGroovyLib2.3/groovy-all-2.3.0.jar Binary files differindex 3b5173f970df..720d4a962bac 100644 --- a/plugins/groovy/testdata/mockGroovyLib2.3/groovy-all-2.3.0.jar +++ b/plugins/groovy/testdata/mockGroovyLib2.3/groovy-all-2.3.0.jar diff --git a/plugins/hg4idea/resources/org/zmlx/hg4idea/HgVcsMessages.properties b/plugins/hg4idea/resources/org/zmlx/hg4idea/HgVcsMessages.properties index 1531965a2445..5f5a1679709f 100644 --- a/plugins/hg4idea/resources/org/zmlx/hg4idea/HgVcsMessages.properties +++ b/plugins/hg4idea/resources/org/zmlx/hg4idea/HgVcsMessages.properties @@ -132,3 +132,4 @@ hg4idea.changelist.column.branch=Branch hg4idea.annotation.tool.tip=commit {0}\nAuthor: {1}\nDate: {2}\n\n{3} hg4idea.push.asNewBranch=push as &new remote branch +hg4idea.push.bookmark=Book&mark diff --git a/plugins/hg4idea/src/META-INF/plugin.xml b/plugins/hg4idea/src/META-INF/plugin.xml index ba40408dd98d..f0ce13c23b43 100644 --- a/plugins/hg4idea/src/META-INF/plugin.xml +++ b/plugins/hg4idea/src/META-INF/plugin.xml @@ -1,7 +1,17 @@ <idea-plugin> <id>hg4idea</id> <name>hg4idea</name> - <description>Provides integration with Mercurial version control system. Supports Mercurial 1.3+.</description> + <description> + <![CDATA[ + Allows working with <a href="http://mercurial.selenic.com/">Mercurial version control system</a>. + The following features are available: + <ul> + <li>Dedicated page under the Version Control node in the Settings/Preferences dialog.</li> + <li>Ability to browse, check out sources from and import into the available Mercurial repositories, when Mercurial is not enabled.</li> + <li>When Mercurial is enabled, the Mercurial node appears on the VCS menu, and on the context menu of the editor. + </ul> + ]]> + </description> <category>VCS Integration</category> <version>10.0</version> <vendor email="victor.iacoban@gmail.com, willem.verstraeten@gmail.com" url="http://www.bitbucket.org/willemv/hg4idea">Victor Iacoban and Willem Verstraeten</vendor> diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java index 9c10a51a7145..17d4f364a154 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java @@ -23,27 +23,21 @@ import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.action.HgCommandResultNotifier; import org.zmlx.hg4idea.command.HgPushCommand; -import org.zmlx.hg4idea.command.HgTagBranch; -import org.zmlx.hg4idea.command.HgTagBranchCommand; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.ui.HgPushDialog; -import org.zmlx.hg4idea.util.HgUtil; -import java.util.Collections; +import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; -/** - * @author Kirill Likhodedov - */ public class HgPusher { private static final Logger LOG = Logger.getInstance(HgPusher.class); @@ -59,52 +53,27 @@ public class HgPusher { myProject = project; } - public void showDialogAndPush(@Nullable final VirtualFile selectedRepo) { - HgUtil.executeOnPooledThreadIfNeeded(new Runnable() { - public void run() { - final List<VirtualFile> repositories = HgUtil.getHgRepositories(myProject); - if (repositories.isEmpty()) { - VcsBalloonProblemNotifier.showOverChangesView(myProject, "No Mercurial repositories in the project", MessageType.ERROR); - return; - } - VirtualFile firstRepo = repositories.get(0); - final List<HgTagBranch> branches = getBranches(myProject, firstRepo); - if (branches.isEmpty()) { - return; - } - final AtomicReference<HgPushCommand> pushCommand = new AtomicReference<HgPushCommand>(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - final HgPushDialog dialog = new HgPushDialog(myProject, repositories, branches, selectedRepo); - dialog.show(); - if (dialog.isOK()) { - dialog.rememberSettings(); - pushCommand.set(preparePushCommand(myProject, dialog)); - new Task.Backgroundable(myProject, "Pushing...", false) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - if (pushCommand.get() != null) { - push(myProject, pushCommand.get()); - } - } - }.queue(); - } - } - }); - } - }); - } + public void showDialogAndPush (@NotNull Collection<HgRepository> repositories,@Nullable final HgRepository selectedRepo) { - @NotNull - public static List<HgTagBranch> getBranches(@NotNull Project project, @NotNull VirtualFile root) { - HgCommandResult branchesResult = new HgTagBranchCommand(project, root).collectBranches(); - if (branchesResult == null) { - new HgCommandResultNotifier(project) - .notifyError(branchesResult, "Mercurial command failed", HgVcsMessages.message("hg4idea.branches.error.description")); - return Collections.emptyList(); + if (repositories.isEmpty()) { + VcsBalloonProblemNotifier.showOverChangesView(myProject, "No Mercurial repositories in the project", MessageType.ERROR); + return; + } + final AtomicReference<HgPushCommand> pushCommand = new AtomicReference<HgPushCommand>(); + final HgPushDialog dialog = new HgPushDialog(myProject, repositories, selectedRepo); + dialog.show(); + if (dialog.isOK()) { + dialog.rememberSettings(); + pushCommand.set(preparePushCommand(myProject, dialog)); + new Task.Backgroundable(myProject, "Pushing...", false) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + if (pushCommand.get() != null) { + push(myProject, pushCommand.get()); + } + } + }.queue(); } - return HgTagBranchCommand.parseResult(branchesResult); } private static void push(final Project project, HgPushCommand command) { @@ -122,9 +91,11 @@ public class HgPusher { String successDescription = String.format("Pushed %d %s [%s]", commitsNum, StringUtil.pluralize("commit", commitsNum), repo.getPresentableName()); new HgCommandResultNotifier(project).notifySuccess(successTitle, successDescription); - } else if (result.getExitValue() == NOTHING_TO_PUSH_EXIT_VALUE) { + } + else if (result.getExitValue() == NOTHING_TO_PUSH_EXIT_VALUE) { new HgCommandResultNotifier(project).notifySuccess("", "Nothing to push"); - } else { + } + else { new HgCommandResultNotifier(project).notifyError(result, "Push failed", "Failed to push to [" + repo.getPresentableName() + "]"); } @@ -133,10 +104,11 @@ public class HgPusher { } private static HgPushCommand preparePushCommand(Project project, HgPushDialog dialog) { - final HgPushCommand command = new HgPushCommand(project, dialog.getRepository(), dialog.getTarget()); + final HgPushCommand command = new HgPushCommand(project, dialog.getRepository().getRoot(), dialog.getTarget()); command.setRevision(dialog.getRevision()); command.setForce(dialog.isForce()); - command.setBranch(dialog.getBranch()); + command.setBranchName(dialog.getBranch()); + command.setBookmarkName(dialog.getBookmarkName()); command.setIsNewBranch(dialog.isNewBranch()); return command; } @@ -159,5 +131,4 @@ public class HgPusher { } return numberOfCommitsInAllSubrepos; } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java index 3db5f19df3d9..9984facc8037 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java @@ -23,6 +23,8 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgVcs; +import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.repo.HgRepositoryManager; import org.zmlx.hg4idea.util.HgUtil; import javax.swing.*; @@ -47,10 +49,11 @@ abstract class HgAbstractGlobalAction extends AnAction { return; } VirtualFile file = event.getData(CommonDataKeys.VIRTUAL_FILE); - VirtualFile repo = file != null ? HgUtil.getHgRootOrNull(project, file) : null; - List<VirtualFile> repos = HgUtil.getHgRepositories(project); - if (!repos.isEmpty()) { - execute(project, repos, repo); + HgRepositoryManager repositoryManager = HgUtil.getRepositoryManager(project); + HgRepository repo = file != null ? repositoryManager.getRepositoryForFile(file): HgUtil.getCurrentRepository(project); + List<HgRepository> repositories = repositoryManager.getRepositories(); + if (!repositories.isEmpty()) { + execute(project, repositories, repo); } } @@ -62,8 +65,8 @@ abstract class HgAbstractGlobalAction extends AnAction { } protected abstract void execute(@NotNull Project project, - @NotNull Collection<VirtualFile> repositories, - @Nullable VirtualFile selectedRepo); + @NotNull Collection<HgRepository> repositories, + @Nullable HgRepository selectedRepo); public static void handleException(@Nullable Project project, @NotNull Exception e) { handleException(project, "Error", e); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAction.java deleted file mode 100644 index 6660d104f49e..000000000000 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAction.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.zmlx.hg4idea.action; - -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.util.HgUtil; - -import javax.swing.*; - -/** - * @author Kirill Likhodedov - */ -public abstract class HgAction extends AnAction { - protected HgAction() { - } - - protected HgAction(Icon icon) { - super(icon); - } - - @Override - public void actionPerformed(AnActionEvent event) { - final DataContext dataContext = event.getDataContext(); - final Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) { - return; - } - VirtualFile file = event.getData(CommonDataKeys.VIRTUAL_FILE); - VirtualFile repo = file != null ? HgUtil.getHgRootOrNull(project, file) : null; - execute(project, repo); - } - - @Override - public void update(AnActionEvent e) { - boolean enabled = HgAbstractGlobalAction.isEnabled(e); - e.getPresentation().setEnabled(enabled); - } - - public abstract void execute(Project project, @Nullable VirtualFile selectedRepo); - -} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchAbstractAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchAbstractAction.java new file mode 100644 index 000000000000..78b67013ed54 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchAbstractAction.java @@ -0,0 +1,36 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zmlx.hg4idea.action; + +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.zmlx.hg4idea.repo.HgRepository; + +public abstract class HgBranchAbstractAction extends DumbAwareAction { + @NotNull protected final Project myProject; + @NotNull protected final HgRepository mySelectedRepository; + @NotNull protected final String myBranchName; + + public HgBranchAbstractAction(@NotNull Project project, @NotNull String title, + @NotNull HgRepository selectedRepository, + @NotNull String branchName) { + super(title); + myProject = project; + mySelectedRepository = selectedRepository; + myBranchName = branchName; + } +}
\ No newline at end of file diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java index b2b4f99fd946..01627240d8e4 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java @@ -23,13 +23,10 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.PlatformIcons; import com.intellij.util.containers.ContainerUtil; @@ -39,14 +36,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgNameWithHashInfo; import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgVcs; -import org.zmlx.hg4idea.HgVcsMessages; -import org.zmlx.hg4idea.command.*; +import org.zmlx.hg4idea.command.HgBookmarkCommand; +import org.zmlx.hg4idea.command.HgBranchCreateCommand; +import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; -import org.zmlx.hg4idea.provider.update.HgConflictResolver; -import org.zmlx.hg4idea.provider.update.HgHeadMerger; import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.ui.HgBookmarkDialog; import org.zmlx.hg4idea.util.HgErrorUtil; @@ -55,9 +50,6 @@ import java.util.*; import static org.zmlx.hg4idea.util.HgUtil.*; -/** - * @author Nadya Zabrodina - */ public class HgBranchPopupActions { private final Project myProject; @@ -80,9 +72,8 @@ public class HgBranchPopupActions { popupGroup.addSeparator("Bookmarks"); List<String> bookmarkNames = getNamesWithoutHashes(myRepository.getBookmarks()); String currentBookmark = myRepository.getCurrentBookmark(); - Collections.sort(bookmarkNames); for (String bookmark : bookmarkNames) { - AnAction bookmarkAction = new BranchActions(myProject, bookmark, myRepository); + AnAction bookmarkAction = new BookmarkActions(myProject, myRepository, bookmark); if (bookmark.equals(currentBookmark)) { bookmarkAction.getTemplatePresentation().setIcon(PlatformIcons.CHECK_ICON); } @@ -94,7 +85,7 @@ public class HgBranchPopupActions { Collections.sort(branchNamesList); for (String branch : branchNamesList) { if (!branch.equals(myRepository.getCurrentBranch())) { // don't show current branch in the list - popupGroup.add(new BranchActions(myProject, branch, myRepository)); + popupGroup.add(new HgCommonBranchActions(myProject, myRepository, branch)); } } return popupGroup; @@ -160,17 +151,7 @@ public class HgBranchPopupActions { if (bookmarkDialog.isOK()) { try { final String name = bookmarkDialog.getName(); - new HgBookmarkCreateCommand(myProject, myPreselectedRepo, name, - bookmarkDialog.isActive()).execute(new HgCommandResultHandler() { - @Override - public void process(@Nullable HgCommandResult result) { - getRepositoryManager(myProject).updateRepository(myPreselectedRepo); - if (HgErrorUtil.hasErrorsInCommandExecution(result)) { - new HgCommandResultNotifier(myProject) - .notifyError(result, "Creation failed", "Bookmark creation [" + name + "] failed"); - } - } - }); + new HgBookmarkCommand(myProject, myPreselectedRepo, name).createBookmark(bookmarkDialog.isActive()); } catch (HgCommandException exception) { HgAbstractGlobalAction.handleException(myProject, exception); @@ -229,7 +210,7 @@ public class HgBranchPopupActions { public AnAction[] getChildren(@Nullable AnActionEvent e) { List<AnAction> branchHeadActions = new ArrayList<AnAction>(); for (Hash hash : myHeads) { - branchHeadActions.add(new BranchActions(myProject, hash.toShortString(), myRepository)); + branchHeadActions.add(new HgCommonBranchActions(myProject, myRepository, hash.toShortString())); } return ContainerUtil.toArray(branchHeadActions, new AnAction[branchHeadActions.size()]); } @@ -246,117 +227,35 @@ public class HgBranchPopupActions { } } - /** - * Actions available for branches. + * Actions available for bookmarks. */ - static class BranchActions extends ActionGroup { - - private final Project myProject; - private String myBranchName; - @NotNull private final HgRepository mySelectedRepository; - - BranchActions(@NotNull Project project, @NotNull String branchName, - @NotNull HgRepository selectedRepository) { - super("", true); - myProject = project; - myBranchName = branchName; - mySelectedRepository = selectedRepository; - getTemplatePresentation().setText(calcBranchText(), false); // no mnemonics - } + static class BookmarkActions extends HgCommonBranchActions { - @NotNull - private String calcBranchText() { - return myBranchName; + BookmarkActions(@NotNull Project project, @NotNull HgRepository selectedRepository, @NotNull String branchName) { + super(project, selectedRepository, branchName); } @NotNull @Override public AnAction[] getChildren(@Nullable AnActionEvent e) { - return new AnAction[]{ - new UpdateToAction(myProject, mySelectedRepository, myBranchName), - new MergeAction(myProject, mySelectedRepository, myBranchName) - }; + return ArrayUtil.append(super.getChildren(e), new DeleteBookmarkAction(myProject, mySelectedRepository, myBranchName)); } - private static class MergeAction extends DumbAwareAction { - - private final Project myProject; - private final HgRepository mySelectedRepository; - private final String myBranchName; + private static class DeleteBookmarkAction extends HgBranchAbstractAction { - public MergeAction(@NotNull Project project, - @NotNull HgRepository selectedRepository, - @NotNull String branchName) { - super("Merge"); - myProject = project; - mySelectedRepository = selectedRepository; - myBranchName = branchName; + DeleteBookmarkAction(@NotNull Project project, @NotNull HgRepository selectedRepository, @NotNull String branchName) { + super(project, "Delete", selectedRepository, branchName); } @Override public void actionPerformed(AnActionEvent e) { - final UpdatedFiles updatedFiles = UpdatedFiles.create(); - final HgMergeCommand hgMergeCommand = new HgMergeCommand(myProject, mySelectedRepository.getRoot()); - hgMergeCommand.setBranch(myBranchName); - final HgCommandResultNotifier notifier = new HgCommandResultNotifier(myProject); - new Task.Backgroundable(myProject, "Merging changes...") { - @Override - public void run(@NotNull ProgressIndicator indicator) { - try { - new HgHeadMerger(myProject, hgMergeCommand) - .merge(mySelectedRepository.getRoot(), updatedFiles, HgRevisionNumber.NULL_REVISION_NUMBER); - new HgConflictResolver(myProject, updatedFiles).resolve(mySelectedRepository.getRoot()); - } - - catch (VcsException exception) { - if (exception.isWarning()) { - notifier.notifyWarning("Warning during merge", exception.getMessage()); - } - else { - notifier.notifyError(null, "Exception during merge", exception.getMessage()); - } - } - catch (Exception e1) { - HgAbstractGlobalAction.handleException(myProject, e1); - } - } - }.queue(); - } - } - - private static class UpdateToAction extends DumbAwareAction { - - @NotNull private final Project myProject; - @NotNull private final HgRepository mySelectedRepository; - @NotNull private final String myBranch; - - public UpdateToAction(@NotNull Project project, - @NotNull HgRepository selectedRepository, - @NotNull String branch) { - super("Update To"); - myProject = project; - mySelectedRepository = selectedRepository; - myBranch = branch; - } - - @Override - public void actionPerformed(AnActionEvent e) { - final VirtualFile repository = mySelectedRepository.getRoot(); - final HgUpdateCommand hgUpdateCommand = new HgUpdateCommand(myProject, repository); - hgUpdateCommand.setBranch(myBranch); - new Task.Backgroundable(myProject, HgVcsMessages.message("action.hg4idea.updateTo.description", myBranch)) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - HgCommandResult result = hgUpdateCommand.execute(); - assert myProject != null; // myProject couldn't be null, see annotation for updateTo action - if (HgErrorUtil.hasErrorsInCommandExecution(result)) { - new HgCommandResultNotifier(myProject).notifyError(result, "", "Update failed"); - new HgConflictResolver(myProject).resolve(repository); - } - myProject.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, null); - } - }.queue(); + try { + new HgBookmarkCommand(myProject, mySelectedRepository.getRoot(), myBranchName).deleteBookmark(); + } + catch (HgCommandException exception) { + HgAbstractGlobalAction.handleException(myProject, exception); + } } } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java index 61cf991c20a5..b8a10ed92116 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java @@ -16,34 +16,18 @@ package org.zmlx.hg4idea.action; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.repo.HgRepository; -import org.zmlx.hg4idea.util.HgUtil; import java.util.Collection; -/** - * @author Nadya Zabrodina - */ - public class HgBranchesAction extends HgAbstractGlobalAction { @Override - protected void execute(@NotNull Project project, @NotNull Collection<VirtualFile> repositories, @Nullable VirtualFile selectedRepo) { - HgRepository repository = null; + protected void execute(@NotNull Project project, @NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) { if (selectedRepo != null) { - repository = HgUtil.getRepositoryManager(project).getRepositoryForRoot(selectedRepo); - } - else { - VirtualFile selectedRoot = HgUtil.getRootForSelectedFile(project); - if (selectedRoot != null) { - repository = HgUtil.getRepositoryManager(project).getRepositoryForRoot(selectedRoot); - } - } - if (repository != null) { - HgBranchPopup.getInstance(project, repository).asListPopup().showInFocusCenter(); + HgBranchPopup.getInstance(project, selectedRepo).asListPopup().showInFocusCenter(); } } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommonBranchActions.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommonBranchActions.java new file mode 100644 index 000000000000..992a26c6ab5e --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommonBranchActions.java @@ -0,0 +1,129 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zmlx.hg4idea.action; + +import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.update.UpdatedFiles; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.HgVcs; +import org.zmlx.hg4idea.HgVcsMessages; +import org.zmlx.hg4idea.command.HgMergeCommand; +import org.zmlx.hg4idea.command.HgUpdateCommand; +import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.provider.update.HgConflictResolver; +import org.zmlx.hg4idea.provider.update.HgHeadMerger; +import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.util.HgErrorUtil; + +public class HgCommonBranchActions extends ActionGroup { + + @NotNull protected final Project myProject; + @NotNull protected String myBranchName; + @NotNull protected final HgRepository mySelectedRepository; + + HgCommonBranchActions(@NotNull Project project, @NotNull HgRepository selectedRepository, @NotNull String branchName) { + super("", true); + myProject = project; + myBranchName = branchName; + mySelectedRepository = selectedRepository; + getTemplatePresentation().setText(myBranchName, false); // no mnemonics + } + + @NotNull + @Override + public AnAction[] getChildren(@Nullable AnActionEvent e) { + return new AnAction[]{ + new UpdateAction(myProject, mySelectedRepository, myBranchName), + new MergeAction(myProject, mySelectedRepository, myBranchName) + }; + } + + private static class MergeAction extends HgBranchAbstractAction { + + public MergeAction(@NotNull Project project, + @NotNull HgRepository selectedRepository, + @NotNull String branchName) { + super(project, "Merge", selectedRepository, branchName); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final UpdatedFiles updatedFiles = UpdatedFiles.create(); + final HgMergeCommand hgMergeCommand = new HgMergeCommand(myProject, mySelectedRepository.getRoot()); + hgMergeCommand.setRevision(myBranchName);//there is no difference between branch or revision or bookmark as parameter to merge, + // we need just a string + final HgCommandResultNotifier notifier = new HgCommandResultNotifier(myProject); + new Task.Backgroundable(myProject, "Merging changes...") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + try { + new HgHeadMerger(myProject, hgMergeCommand) + .merge(mySelectedRepository.getRoot()); + new HgConflictResolver(myProject, updatedFiles).resolve(mySelectedRepository.getRoot()); + } + + catch (VcsException exception) { + if (exception.isWarning()) { + notifier.notifyWarning("Warning during merge", exception.getMessage()); + } + else { + notifier.notifyError(null, "Exception during merge", exception.getMessage()); + } + } + catch (Exception e1) { + HgAbstractGlobalAction.handleException(myProject, e1); + } + } + }.queue(); + } + } + + private static class UpdateAction extends HgBranchAbstractAction { + + public UpdateAction(@NotNull Project project, + @NotNull HgRepository selectedRepository, + @NotNull String branchName) { + super(project, "Update", selectedRepository, branchName); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final VirtualFile repository = mySelectedRepository.getRoot(); + final HgUpdateCommand hgUpdateCommand = new HgUpdateCommand(myProject, repository); + hgUpdateCommand.setBranch(myBranchName); + new Task.Backgroundable(myProject, HgVcsMessages.message("action.hg4idea.updateTo.description", myBranchName)) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + HgCommandResult result = hgUpdateCommand.execute(); + assert myProject != null; // myProject couldn't be null, see annotation for updateTo action + if (HgErrorUtil.hasErrorsInCommandExecution(result)) { + new HgCommandResultNotifier(myProject).notifyError(result, "", "Update failed"); + new HgConflictResolver(myProject).resolve(repository); + } + myProject.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, null); + } + }.queue(); + } + } +}
\ No newline at end of file diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java index 1aec1a0e56e4..5c97e3ca9f39 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java @@ -13,13 +13,13 @@ package org.zmlx.hg4idea.action; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.command.HgTagCreateCommand; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.ui.HgTagDialog; import org.zmlx.hg4idea.util.HgErrorUtil; @@ -28,11 +28,10 @@ import java.util.Collection; public class HgCreateTagAction extends HgAbstractGlobalAction { public void execute(@NotNull final Project project, - @NotNull Collection<VirtualFile> repos, - @Nullable VirtualFile selectedRepo, + @NotNull Collection<HgRepository> repositories, + @Nullable HgRepository selectedRepo, @Nullable final String reference) { - final HgTagDialog dialog = new HgTagDialog(project); - dialog.setRoots(repos, selectedRepo); + final HgTagDialog dialog = new HgTagDialog(project, repositories, selectedRepo); dialog.show(); if (dialog.isOK()) { try { @@ -52,7 +51,9 @@ public class HgCreateTagAction extends HgAbstractGlobalAction { } } - protected void execute(@NotNull final Project project, @NotNull Collection<VirtualFile> repos, @Nullable VirtualFile selectedRepo) { - execute(project, repos, selectedRepo, null); + protected void execute(@NotNull final Project project, + @NotNull Collection<HgRepository> repositories, + @Nullable HgRepository selectedRepo) { + execute(project, repositories, selectedRepo, null); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagFromLogAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagFromLogAction.java index 18a42d735046..03f6f951cea7 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagFromLogAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagFromLogAction.java @@ -19,15 +19,12 @@ import com.intellij.vcs.log.VcsFullCommitDetails; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.repo.HgRepository; -import java.util.Arrays; +import java.util.Collections; -/** - * @author Nadya Zabrodina - */ public class HgCreateTagFromLogAction extends HgLogSingleCommitAction { @Override protected void actionPerformed(@NotNull HgRepository repository, @NotNull VcsFullCommitDetails commit) { String revisionHash = commit.getHash().asString(); - new HgCreateTagAction().execute(repository.getProject(), Arrays.asList(repository.getRoot()), repository.getRoot(), revisionHash); + new HgCreateTagAction().execute(repository.getProject(), Collections.singleton(repository), repository, revisionHash); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMerge.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMerge.java index fe022bcfb775..87c907d76d59 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMerge.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMerge.java @@ -18,56 +18,37 @@ package org.zmlx.hg4idea.action; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgVcsMessages; import org.zmlx.hg4idea.command.HgMergeCommand; -import org.zmlx.hg4idea.command.HgTagBranch; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.provider.update.HgConflictResolver; import org.zmlx.hg4idea.provider.update.HgHeadMerger; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.ui.HgMergeDialog; -import org.zmlx.hg4idea.util.HgBranchesAndTags; -import org.zmlx.hg4idea.util.HgUiUtil; import java.util.Collection; -/** - * @author Nadya Zabrodina - */ public class HgMerge extends HgAbstractGlobalAction { @Override public void execute(@NotNull final Project project, - @NotNull final Collection<VirtualFile> repos, - @Nullable final VirtualFile selectedRepo) { - HgUiUtil.loadBranchesInBackgroundableAndExecuteAction(project, repos, new Consumer<HgBranchesAndTags>() { - - @Override - public void consume(HgBranchesAndTags info) { - showMergeDialogAndExecute(project, repos, selectedRepo, info); - } - }); - } - - private void showMergeDialogAndExecute(final Project project, - Collection<VirtualFile> repos, - @Nullable VirtualFile selectedRepo, HgBranchesAndTags branchesAndTags) { - final HgMergeDialog mergeDialog = new HgMergeDialog(project, repos, selectedRepo, branchesAndTags); + @NotNull final Collection<HgRepository> repos, + @Nullable final HgRepository selectedRepo) { + final HgMergeDialog mergeDialog = new HgMergeDialog(project, repos, selectedRepo); mergeDialog.show(); if (mergeDialog.isOK()) { + final String targetValue = mergeDialog.getTargetValue(); + final VirtualFile repoRoot = mergeDialog.getRepository().getRoot(); new Task.Backgroundable(project, "Merging changes...") { @Override public void run(@NotNull ProgressIndicator indicator) { try { - executeMerge(mergeDialog, project); - markDirtyAndHandleErrors(project, mergeDialog.getRepository()); + executeMerge(project, repoRoot, targetValue); + markDirtyAndHandleErrors(project, repoRoot); } catch (HgCommandException e) { handleException(project, e); @@ -77,63 +58,26 @@ public class HgMerge extends HgAbstractGlobalAction { } } - private static void executeMerge(final HgMergeDialog dialog, final Project project) throws HgCommandException { + + private static void executeMerge(@NotNull final Project project, @NotNull VirtualFile repo, @NotNull String targetValue) + throws HgCommandException { UpdatedFiles updatedFiles = UpdatedFiles.create(); HgCommandResultNotifier notifier = new HgCommandResultNotifier(project); - final VirtualFile repo = dialog.getRepository(); HgMergeCommand hgMergeCommand = new HgMergeCommand(project, repo); + hgMergeCommand.setRevision(targetValue); - HgRevisionNumber incomingRevision = null; - HgTagBranch branch = dialog.getBranch(); - if (branch != null) { - hgMergeCommand.setBranch(branch.getName()); - incomingRevision = branch.getHead(); - } - - HgTagBranch tag = dialog.getTag(); - if (tag != null) { - hgMergeCommand.setRevision(tag.getName()); - incomingRevision = tag.getHead(); - } - - HgTagBranch bookmark = dialog.getBookmark(); - if (bookmark != null) { - hgMergeCommand.setRevision(bookmark.getName()); - incomingRevision = bookmark.getHead(); - } - - String revision = dialog.getRevision(); - if (revision != null) { - hgMergeCommand.setRevision(revision); - incomingRevision = HgRevisionNumber.getLocalInstance(revision); - } - - HgRevisionNumber otherHead = dialog.getOtherHead(); - if (otherHead != null) { - String changeset = otherHead.getChangeset(); - hgMergeCommand.setRevision(StringUtil.isEmptyOrSpaces(changeset) ? otherHead.getRevision() : changeset); - incomingRevision = otherHead; + try { + new HgHeadMerger(project, hgMergeCommand).merge(repo); + new HgConflictResolver(project, updatedFiles).resolve(repo); } - - if (incomingRevision != null) { - try { - new HgHeadMerger(project, hgMergeCommand) - .merge(repo, updatedFiles, incomingRevision); - new HgConflictResolver(project, updatedFiles).resolve(repo); + catch (VcsException e) { + if (e.isWarning()) { + notifier.notifyWarning("Warning during merge", e.getMessage()); } - catch (VcsException e) { - if (e.isWarning()) { - notifier.notifyWarning("Warning during merge", e.getMessage()); - } - else { - notifier.notifyError(null, "Exception during merge", e.getMessage()); - } + else { + notifier.notifyError(null, "Exception during merge", e.getMessage()); } } - else { - //noinspection ThrowableInstanceNeverThrown - notifier.notifyError(null, "Merge error", HgVcsMessages.message("hg4idea.error.invalidTarget")); - } } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java index 136a50e69809..557d3cfab286 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java @@ -16,10 +16,10 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.command.HgPullCommand; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.ui.HgPullDialog; import java.util.Collection; @@ -30,9 +30,8 @@ public class HgPullAction extends HgAbstractGlobalAction { } @Override - protected void execute(@NotNull final Project project, @NotNull Collection<VirtualFile> repos, @Nullable VirtualFile selectedRepo) { - final HgPullDialog dialog = new HgPullDialog(project); - dialog.setRoots(repos, selectedRepo); + protected void execute(@NotNull final Project project, @NotNull Collection<HgRepository> repos, @Nullable HgRepository selectedRepo) { + final HgPullDialog dialog = new HgPullDialog(project, repos, selectedRepo); dialog.show(); if (dialog.isOK()) { dialog.rememberSettings(); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java index ae6206c7a253..1b5704f1d0f4 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java @@ -14,18 +14,22 @@ package org.zmlx.hg4idea.action; import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgPusher; +import org.zmlx.hg4idea.repo.HgRepository; -public class HgPushAction extends HgAction { +import java.util.Collection; + +public class HgPushAction extends HgAbstractGlobalAction { public HgPushAction() { super(AllIcons.Actions.Commit); } @Override - public void execute(final Project project, @Nullable final VirtualFile selectedRepo) { - new HgPusher(project).showDialogAndPush(selectedRepo); + public void execute(@NotNull final Project project, + @NotNull Collection<HgRepository> repositories, + @Nullable final HgRepository selectedRepo) { + new HgPusher(project).showDialogAndPush(repositories, selectedRepo); } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java index 3be82ada2a8d..938413e95356 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgRunConflictResolverAction.java @@ -15,11 +15,12 @@ package org.zmlx.hg4idea.action; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgVcsMessages; import org.zmlx.hg4idea.provider.update.HgConflictResolver; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.ui.HgRunConflictResolverDialog; import java.util.Collection; @@ -27,39 +28,26 @@ import java.util.Collection; public class HgRunConflictResolverAction extends HgAbstractGlobalAction { @Override - public void execute(@NotNull final Project project, @NotNull Collection<VirtualFile> repos, @Nullable VirtualFile selectedRepo) { - final VirtualFile repository; - if (repos.size() > 1) { - repository = letUserSelectRepository(repos, project, selectedRepo); - } - else if (repos.size() == 1) { - repository = repos.iterator().next(); - } - else { - repository = null; - } + public void execute(@NotNull final Project project, @NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) { + final HgRepository repository = repositories.size() > 1 ? letUserSelectRepository(project, repositories, selectedRepo) : + ContainerUtil.getFirstItem(repositories); if (repository != null) { new Task.Backgroundable(project, HgVcsMessages.message("action.hg4idea.run.conflict.resolver.description")) { @Override public void run(@NotNull ProgressIndicator indicator) { - new HgConflictResolver(project).resolve(repository); - markDirtyAndHandleErrors(project, repository); + new HgConflictResolver(project).resolve(repository.getRoot()); + markDirtyAndHandleErrors(project, repository.getRoot()); } }.queue(); } } - - private static VirtualFile letUserSelectRepository(Collection<VirtualFile> repos, Project project, @Nullable VirtualFile selectedRepo) { - HgRunConflictResolverDialog dialog = new HgRunConflictResolverDialog(project); - dialog.setRoots(repos, selectedRepo); + @Nullable + private static HgRepository letUserSelectRepository(@NotNull Project project, @NotNull Collection<HgRepository> repositories, + @Nullable HgRepository selectedRepo) { + HgRunConflictResolverDialog dialog = new HgRunConflictResolverDialog(project, repositories, selectedRepo); dialog.show(); - if (dialog.isOK()) { - return dialog.getRepository(); - } - else { - return null; - } + return dialog.isOK() ? dialog.getRepository() : null; } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgUpdateToAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgUpdateToAction.java index 1a2cdeae8b55..7e1025921234 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgUpdateToAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgUpdateToAction.java @@ -17,61 +17,43 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgVcsMessages; import org.zmlx.hg4idea.command.HgUpdateCommand; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.provider.update.HgConflictResolver; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.ui.HgUpdateToDialog; -import org.zmlx.hg4idea.util.HgBranchesAndTags; import org.zmlx.hg4idea.util.HgErrorUtil; -import org.zmlx.hg4idea.util.HgUiUtil; import java.util.Collection; public class HgUpdateToAction extends HgAbstractGlobalAction { - protected void execute(@NotNull final Project project, - @NotNull final Collection<VirtualFile> repos, - @Nullable final VirtualFile selectedRepo) { - HgUiUtil.loadBranchesInBackgroundableAndExecuteAction(project, repos, new Consumer<HgBranchesAndTags>() { - @Override - public void consume(HgBranchesAndTags info) { - showUpdateDialogAndExecute(project, repos, selectedRepo, info); - } - }); - } - - private static void showUpdateDialogAndExecute(@NotNull final Project project, - @NotNull Collection<VirtualFile> repos, @Nullable VirtualFile selectedRepo, - @NotNull HgBranchesAndTags branchesAndTags) { - final HgUpdateToDialog dialog = new HgUpdateToDialog(project); - dialog.setRoots(repos, selectedRepo, branchesAndTags); + @Override + protected void execute(@NotNull Project project, @NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) { + final HgUpdateToDialog dialog = new HgUpdateToDialog(project, repositories, selectedRepo); dialog.show(); if (dialog.isOK()) { FileDocumentManager.getInstance().saveAllDocuments(); - final String updateToValue = dialog.isBranchSelected() - ? dialog.getBranch().getName() - : dialog.isBookmarkSelected() - ? dialog.getBookmark().getName() - : dialog.isTagSelected() ? dialog.getTag().getName() : dialog.getRevision(); + final String updateToValue = dialog.getTargetValue(); + boolean clean = dialog.isRemoveLocalChanges(); String title = HgVcsMessages.message("hg4idea.progress.updatingTo", updateToValue); - runUpdateToInBackground(project, title, dialog.getRepository(), updateToValue, dialog.isRemoveLocalChanges()); + runUpdateToInBackground(project, title, dialog.getRepository().getRoot(), updateToValue, clean); } } public static void runUpdateToInBackground(@NotNull final Project project, @NotNull String title, @NotNull final VirtualFile root, - @NotNull final String updateToNameOrRevision, + @NotNull final String updateToValue, final boolean clean) { new Task.Backgroundable(project, title) { @Override public void run(@NotNull ProgressIndicator indicator) { final HgUpdateCommand command = new HgUpdateCommand(project, root); - command.setRevision(updateToNameOrRevision); + command.setRevision(updateToValue); command.setClean(clean); HgCommandResult result = command.execute(); new HgConflictResolver(project).resolve(root); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgBookmarkCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgBookmarkCommand.java new file mode 100644 index 000000000000..21b4edd2d7cb --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgBookmarkCommand.java @@ -0,0 +1,65 @@ +package org.zmlx.hg4idea.command; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.action.HgCommandResultNotifier; +import org.zmlx.hg4idea.execution.HgCommandException; +import org.zmlx.hg4idea.execution.HgCommandExecutor; +import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.execution.HgCommandResultHandler; +import org.zmlx.hg4idea.util.HgErrorUtil; + +import java.util.List; + +import static org.zmlx.hg4idea.util.HgUtil.getRepositoryManager; + +public class HgBookmarkCommand { + @NotNull private final Project myProject; + @NotNull private final VirtualFile myRepo; + @Nullable private final String myBookmarkName; + @NotNull private final HgCommandResultHandler myBookmarkResultHandler; + + public HgBookmarkCommand(@NotNull Project project, + @NotNull VirtualFile repo, + @Nullable String bookmarkName) { + myProject = project; + myRepo = repo; + myBookmarkName = bookmarkName; + myBookmarkResultHandler = new HgCommandResultHandler() { + @Override + public void process(@Nullable HgCommandResult result) { + getRepositoryManager(myProject).updateRepository(myRepo); + if (HgErrorUtil.hasErrorsInCommandExecution(result)) { + new HgCommandResultNotifier(myProject) + .notifyError(result, "Hg Error", "Hg bookmark command failed for " + myBookmarkName); + } + } + }; + } + + public void createBookmark(boolean isActive) throws HgCommandException { + if (isActive) { + executeBookmarkCommand(); + } + else { + executeBookmarkCommand("--inactive"); + } + } + + public void deleteBookmark() throws HgCommandException { + executeBookmarkCommand("-d"); //delete + } + + private void executeBookmarkCommand(@NotNull String... args) throws HgCommandException { + if (StringUtil.isEmptyOrSpaces(myBookmarkName)) { + throw new HgCommandException("bookmark name is empty"); + } + List<String> arguments = ContainerUtil.newArrayList(args); + arguments.add(myBookmarkName); + new HgCommandExecutor(myProject).execute(myRepo, "bookmark", arguments, myBookmarkResultHandler); + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgBookmarkCreateCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgBookmarkCreateCommand.java deleted file mode 100644 index 89442efbc35e..000000000000 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgBookmarkCreateCommand.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.zmlx.hg4idea.command; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.execution.HgCommandException; -import org.zmlx.hg4idea.execution.HgCommandExecutor; -import org.zmlx.hg4idea.execution.HgCommandResultHandler; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Nadya Zabrodina - */ -public class HgBookmarkCreateCommand { - @NotNull private final Project myProject; - @NotNull private final VirtualFile myRepo; - @Nullable private final String myBookmarkName; - private final boolean isActive; - - public HgBookmarkCreateCommand(@NotNull Project project, - @NotNull VirtualFile repo, - @Nullable String bookmarkName, - boolean active) { - myProject = project; - myRepo = repo; - myBookmarkName = bookmarkName; - isActive = active; - } - - public void execute(@Nullable HgCommandResultHandler resultHandler) throws HgCommandException { - if (StringUtil.isEmptyOrSpaces(myBookmarkName)) { - throw new HgCommandException("bookmark name is empty"); - } - List<String> arguments = new ArrayList<String>(); - arguments.add(myBookmarkName); - if (!isActive) { - arguments.add("--inactive"); - } - new HgCommandExecutor(myProject).execute(myRepo, "bookmark", arguments, resultHandler); - } -} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTagBranchCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgBranchesCommand.java index 7c1aa067b20d..430e7e10b58d 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTagBranchCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgBranchesCommand.java @@ -17,72 +17,31 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgRevisionNumber; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; -import java.util.LinkedList; -import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class HgTagBranchCommand { +public class HgBranchesCommand { private static final Pattern BRANCH_LINE = Pattern.compile("(.+)\\s([0-9]+):([0-9a-f]+).*"); private static final int NAME_INDEX = 1; - private static final int REVISION_INDEX = 2; - private static final int CHANGESET_INDEX = 3; private final Project project; private final VirtualFile repo; - public HgTagBranchCommand(Project project, @NotNull VirtualFile repo) { + public HgBranchesCommand(Project project, @NotNull VirtualFile repo) { this.project = project; this.repo = repo; } @Nullable - public String getCurrentBranch() { - final HgCommandExecutor executor = new HgCommandExecutor(project); - executor.setSilent(true); - HgCommandResult result = executor.executeInCurrentThread(repo, "branch", null); - if (result == null) { - return null; - } - List<String> output = result.getOutputLines(); - if (output == null || output.isEmpty()) { - return null; - } - return output.get(0).trim(); - } - public HgCommandResult collectBranches() { return new HgCommandExecutor(project).executeInCurrentThread(repo, "branches", null); } - public HgCommandResult collectTags() { - return new HgCommandExecutor(project).executeInCurrentThread(repo, "tags", null); - } - - public HgCommandResult collectBookmarks() { - return new HgCommandExecutor(project).executeInCurrentThread(repo, "bookmarks", null); - } - - public static List<HgTagBranch> parseResult(@NotNull HgCommandResult result) { - List<HgTagBranch> branches = new LinkedList<HgTagBranch>(); - for (final String line : result.getOutputLines()) { - Matcher matcher = BRANCH_LINE.matcher(line); - if (matcher.matches()) { - HgRevisionNumber hgRevisionNumber = HgRevisionNumber.getInstance( - matcher.group(REVISION_INDEX), matcher.group(CHANGESET_INDEX) - ); - branches.add(new HgTagBranch(matcher.group(NAME_INDEX).trim(), line.trim(), hgRevisionNumber)); - } - } - return branches; - } - @NotNull public static Set<String> collectNames(@NotNull HgCommandResult result) { Set<String> branches = new HashSet<String>(); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgMergeCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgMergeCommand.java index d8d70f0c5cc8..ad10a373de4e 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgMergeCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgMergeCommand.java @@ -15,6 +15,7 @@ package org.zmlx.hg4idea.command; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.execution.HgCommandExecutor; @@ -26,22 +27,17 @@ import java.util.List; public class HgMergeCommand { - private final Project project; - private final VirtualFile repo; + @NotNull private final Project project; + @NotNull private final VirtualFile repo; - private String branch; private String revision; - public HgMergeCommand(Project project, VirtualFile repo) { + public HgMergeCommand(@NotNull Project project, @NotNull VirtualFile repo) { this.project = project; this.repo = repo; } - public void setBranch(String branch) { - this.branch = branch; - } - - public void setRevision(String revision) { + public void setRevision(@NotNull String revision) { this.revision = revision; } @@ -53,13 +49,10 @@ public class HgMergeCommand { if (!StringUtil.isEmptyOrSpaces(revision)) { arguments.add("--rev"); arguments.add(revision); - } else if (!StringUtil.isEmptyOrSpaces(branch)) { - arguments.add(branch); } final HgCommandResult result = commandExecutor.executeInCurrentThread(repo, "merge", arguments, new HgDeleteModifyPromptHandler()); project.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(project, null); return result; } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgPushCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgPushCommand.java index 357fa891201a..16748462a45f 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgPushCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgPushCommand.java @@ -33,7 +33,8 @@ public class HgPushCommand { private String myRevision; private boolean myForce; - private HgTagBranch myBranch; + private String myBranchName; + private String myBookmarkName; private boolean myIsNewBranch; public HgPushCommand(Project project, @NotNull VirtualFile repo, String destination) { @@ -50,13 +51,17 @@ public class HgPushCommand { myForce = force; } - public void setBranch(HgTagBranch branch) { - myBranch = branch; + public void setBranchName(String branchName) { + myBranchName = branchName; } public void setIsNewBranch(boolean isNewBranch) { - myIsNewBranch = isNewBranch; - } + myIsNewBranch = isNewBranch; + } + + public void setBookmarkName(String bookmark) { + myBookmarkName = bookmark; + } public void execute(final HgCommandResultHandler resultHandler) { final List<String> arguments = new LinkedList<String>(); @@ -64,15 +69,19 @@ public class HgPushCommand { arguments.add("-r"); arguments.add(myRevision); } - if (myBranch != null) { + if (myBranchName != null) { if (myIsNewBranch) { arguments.add("--new-branch"); } else { arguments.add("-b"); - arguments.add(myBranch.getName()); + arguments.add(myBranchName); } } + if (!StringUtil.isEmptyOrSpaces(myBookmarkName)) { + arguments.add("-B"); + arguments.add(myBookmarkName); + } if (myForce) { arguments.add("-f"); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTagBranch.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTagBranch.java deleted file mode 100644 index cf4325afdcb4..000000000000 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTagBranch.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2008-2010 Victor Iacoban -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software distributed under -// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -// either express or implied. See the License for the specific language governing permissions and -// limitations under the License. -package org.zmlx.hg4idea.command; - -import com.intellij.openapi.util.text.StringUtil; -import org.zmlx.hg4idea.HgRevisionNumber; - -public final class HgTagBranch { - - private static final int SPACINGAFTERFIRSTLETTER = 20; - - private final String name; - private final String description; - private final HgRevisionNumber head; - private final String presentation; - - public HgTagBranch(String name, String description, HgRevisionNumber head) { - this.name = name; - this.description = description; - this.head = head; - int whitespaceNum = SPACINGAFTERFIRSTLETTER - name.length(); - String presentationName = whitespaceNum <= 0 ? name.substring(0, SPACINGAFTERFIRSTLETTER - 4).concat("...") : name; - presentation = String.format("%s%s%s", presentationName, whitespaceNum > 0 ? StringUtil.repeatSymbol(' ', whitespaceNum) : " ", head); - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public HgRevisionNumber getHead() { - return head; - } - - @Override - public String toString() { - return presentation; - } -} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java index aaf9e9dd1c8b..dec0e720fcdb 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java @@ -40,6 +40,8 @@ import org.zmlx.hg4idea.command.*; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.repo.HgRepositoryManager; import org.zmlx.hg4idea.util.HgUtil; import java.util.*; @@ -125,9 +127,12 @@ public class HgCheckinEnvironment implements CheckinEnvironment { // push if needed if (myNextCommitIsPushed && exceptions.isEmpty()) { final VirtualFile preselectedRepo = repositoriesMap.size() == 1 ? repositoriesMap.keySet().iterator().next() : null; + HgRepositoryManager repositoryManager = HgUtil.getRepositoryManager(myProject); + final HgRepository repo = preselectedRepo != null ? repositoryManager.getRepositoryForFile(preselectedRepo) : null; + final Collection<HgRepository> repositories = repositoryManager.getRepositories(); UIUtil.invokeLaterIfNeeded(new Runnable() { public void run() { - new HgPusher(myProject).showDialogAndPush(preselectedRepo); + new HgPusher(myProject).showDialogAndPush(repositories, repo); } }); } @@ -264,31 +269,33 @@ public class HgCheckinEnvironment implements CheckinEnvironment { public HgCommitAdditionalComponent(@NotNull Project project, @NotNull CheckinProjectPanel panel) { super(project, panel); HgVcs myVcs = HgVcs.getInstance(myProject); - if (myVcs != null && !myVcs.getVersion().isAmendSupported()) { - myAmend.setEnabled(false); - } + myAmend.setEnabled(myVcs != null && myVcs.getVersion().isAmendSupported()); } + @Override public void refresh() { super.refresh(); myNextCommitAmend = false; } + @Override public void saveState() { myNextCommitAmend = myAmend.isSelected(); } + @Override public void restoreState() { myNextCommitAmend = false; } @NotNull @Override - protected Collection<VirtualFile> getRoots() { - return HgUtil.getHgRepositories(myProject); + protected Set<VirtualFile> getVcsRoots(@NotNull Collection<FilePath> filePaths) { + return HgUtil.hgRoots(myProject, filePaths); } @Nullable + @Override protected String getLastCommitMessage(@NotNull VirtualFile repo) throws VcsException { HgCommandExecutor commandExecutor = new HgCommandExecutor(myProject); List<String> args = new ArrayList<String>(); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java index 15ab366f1001..a9df96b07ca3 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java @@ -15,8 +15,6 @@ package org.zmlx.hg4idea.provider.update; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.history.VcsRevisionNumber; -import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.command.HgMergeCommand; @@ -38,11 +36,9 @@ public final class HgHeadMerger { this.hgMergeCommand = hgMergeCommand; } - public HgCommandResult merge(VirtualFile repo, UpdatedFiles updatedFiles, - VcsRevisionNumber revisionNumber) throws VcsException { + public HgCommandResult merge(VirtualFile repo) throws VcsException { HgCommandResult commandResult = ensureSuccess(hgMergeCommand.execute()); - try { HgUtil.markDirectoryDirty(project, repo); } @@ -61,5 +57,4 @@ public final class HgHeadMerger { LOG.info(msg, e); throw new VcsException(msg); } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java index b0b4c7a0ab56..355405f33e7f 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java @@ -113,7 +113,7 @@ public class HgRegularUpdater implements HgUpdater { abortOnMultiplePulledHeads(pulledBranchHeads); abortOnMultipleLocalHeads(remainingOriginalBranchHeads); - HgCommandResult mergeResult = doMerge(updatedFiles, indicator, pulledBranchHeads.get(0)); + HgCommandResult mergeResult = doMerge(indicator); if (shouldCommitAfterMerge()) { commitOrWarnAboutConflicts(warnings, mergeResult); @@ -198,15 +198,13 @@ public class HgRegularUpdater implements HgUpdater { } } - private HgCommandResult doMerge(UpdatedFiles updatedFiles, - ProgressIndicator indicator, - HgRevisionNumber headToMerge) throws VcsException { + private HgCommandResult doMerge(ProgressIndicator indicator) throws VcsException { indicator.setText2(HgVcsMessages.message("hg4idea.update.progress.merging")); HgMergeCommand mergeCommand = new HgMergeCommand(project, repoRoot); //do not explicitly set the revision, that way mercurial itself checks that there are exactly //two heads in this branch // mergeCommand.setRevision(headToMerge.getRevision()); - return new HgHeadMerger(project, mergeCommand).merge(repoRoot, updatedFiles, headToMerge); + return new HgHeadMerger(project, mergeCommand).merge(repoRoot); } private void abortOnLocalChanges() throws VcsException { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java index bef1b6854d1b..fb0036185ebf 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java @@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgNameWithHashInfo; import org.zmlx.hg4idea.HgVcs; -import org.zmlx.hg4idea.command.HgTagBranchCommand; +import org.zmlx.hg4idea.command.HgBranchesCommand; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.util.HgUtil; @@ -162,13 +162,13 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository { // Then blinking and do not work properly; if (!Disposer.isDisposed(getProject()) && !currentInfo.equals(myInfo)) { myInfo = currentInfo; - HgCommandResult branchCommandResult = new HgTagBranchCommand(getProject(), getRoot()).collectBranches(); + HgCommandResult branchCommandResult = new HgBranchesCommand(getProject(), getRoot()).collectBranches(); if (branchCommandResult == null || branchCommandResult.getExitValue() != 0) { LOG.warn("Could not collect hg opened branches."); // hg executable is not valid myOpenedBranches = myInfo.getBranches().keySet(); } else { - myOpenedBranches = HgTagBranchCommand.collectNames(branchCommandResult); + myOpenedBranches = HgBranchesCommand.collectNames(branchCommandResult); } getProject().getMessageBus().syncPublisher(HgVcs.STATUS_TOPIC).update(getProject(), getRoot()); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgUpdateToDialog.form b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgCommonDialogWithChoices.form index 0fe5286fdb5a..1e932fe8a2ba 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgUpdateToDialog.form +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgCommonDialogWithChoices.form @@ -1,16 +1,16 @@ <?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.zmlx.hg4idea.ui.HgUpdateToDialog"> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.zmlx.hg4idea.ui.HgCommonDialogWithChoices"> <grid id="27dc6" binding="contentPanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="500" height="400"/> + <xy x="22" y="20" width="498" height="291"/> </constraints> <properties/> <border type="none"/> <children> <vspacer id="84392"> <constraints> - <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="2" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> </vspacer> <hspacer id="af9e5"> @@ -23,10 +23,14 @@ <grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> + <enabled value="false"/> <text value="&Overwrite locally modified files (no backup)"/> </properties> + <clientProperties> + <html.disable class="java.lang.Boolean" value="false"/> + </clientProperties> </component> - <grid id="814c5" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="814c5" binding="myBranchesBorderPanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> @@ -35,7 +39,7 @@ <clientProperties> <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/> </clientProperties> - <border type="none" title="Switch to"/> + <border type="none"/> <children> <component id="674b0" class="javax.swing.JRadioButton" binding="branchOption"> <constraints> diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgCommonDialogWithChoices.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgCommonDialogWithChoices.java new file mode 100644 index 000000000000..4c7ff6214e94 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgCommonDialogWithChoices.java @@ -0,0 +1,148 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zmlx.hg4idea.ui; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.util.HgUtil; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Collection; + +public class HgCommonDialogWithChoices extends DialogWrapper { + + + private JPanel contentPanel; + private JRadioButton branchOption; + private JRadioButton revisionOption; + private JRadioButton tagOption; + private JRadioButton bookmarkOption; + private JTextField revisionTxt; + protected JCheckBox cleanCbx; + private JComboBox branchSelector; + private JComboBox tagSelector; + private JComboBox bookmarkSelector; + protected HgRepositorySelectorComponent hgRepositorySelectorComponent; + protected JPanel myBranchesBorderPanel; + + public HgCommonDialogWithChoices(@NotNull Project project, @NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) { + super(project, false); + hgRepositorySelectorComponent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + updateRepository(); + } + }); + + ChangeListener changeListener = new ChangeListener() { + public void stateChanged(ChangeEvent e) { + update(); + } + }; + branchOption.addChangeListener(changeListener); + tagOption.addChangeListener(changeListener); + bookmarkOption.addChangeListener(changeListener); + revisionOption.addChangeListener(changeListener); + cleanCbx.setVisible(false); + setRoots(repositories, selectedRepo); + init(); + } + + public void setRoots(Collection<HgRepository> repos, + @Nullable HgRepository selectedRepo) { + hgRepositorySelectorComponent.setRoots(repos); + hgRepositorySelectorComponent.setSelectedRoot(selectedRepo); + updateRepository(); + } + + public HgRepository getRepository() { + return hgRepositorySelectorComponent.getRepository(); + } + + public String getTag() { + return (String)tagSelector.getSelectedItem(); + } + + public boolean isTagSelected() { + return tagOption.isSelected(); + } + + public String getBranch() { + return (String)branchSelector.getSelectedItem(); + } + + public boolean isBranchSelected() { + return branchOption.isSelected(); + } + + public String getBookmark() { + return (String)bookmarkSelector.getSelectedItem(); + } + + public boolean isBookmarkSelected() { + return bookmarkOption.isSelected(); + } + + public String getRevision() { + return revisionTxt.getText(); + } + + private void update() { + revisionTxt.setEnabled(revisionOption.isSelected()); + branchSelector.setEnabled(branchOption.isSelected()); + tagSelector.setEnabled(tagOption.isSelected()); + bookmarkSelector.setEnabled(bookmarkOption.isSelected()); + } + + private void updateRepository() { + HgRepository repo = hgRepositorySelectorComponent.getRepository(); + branchSelector.setModel(new DefaultComboBoxModel(repo.getOpenedBranches().toArray())); + DefaultComboBoxModel tagComboBoxModel = new DefaultComboBoxModel(HgUtil.getNamesWithoutHashes(repo.getTags()).toArray()); + tagComboBoxModel.addElement("tip"); //HgRepository does not store 'tip' tag because it is internal and not included in tags file + tagSelector.setModel(tagComboBoxModel); + bookmarkSelector.setModel(new DefaultComboBoxModel(HgUtil.getNamesWithoutHashes(repo.getBookmarks()).toArray())); + update(); + } + + protected JComponent createCenterPanel() { + return contentPanel; + } + + @Override + protected String getDimensionServiceKey() { + return getClass().getName(); + } + + protected void createUIComponents() { + } + + public String getTargetValue() { + return isBranchSelected() ? getBranch() : isBookmarkSelected() ? getBookmark() : isTagSelected() ? getTag() : getRevision(); + } + + protected ValidationInfo doValidate() { + String message = "You have to specify appropriate name or revision."; + return StringUtil.isEmptyOrSpaces(getTargetValue()) ? new ValidationInfo(message, myBranchesBorderPanel) : null; + } +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMergeDialog.form b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMergeDialog.form deleted file mode 100644 index 5a9411c4b563..000000000000 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMergeDialog.form +++ /dev/null @@ -1,139 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.zmlx.hg4idea.ui.HgMergeDialog"> - <grid id="27dc6" binding="contentPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> - <margin top="0" left="0" bottom="0" right="0"/> - <constraints> - <xy x="20" y="20" width="500" height="400"/> - </constraints> - <properties/> - <border type="none"/> - <children> - <grid id="a0d6" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> - <margin top="0" left="0" bottom="0" right="0"/> - <constraints> - <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> - </constraints> - <properties/> - <clientProperties> - <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/> - </clientProperties> - <border type="none" title="Merge with"/> - <children> - <component id="99075" class="javax.swing.JRadioButton" binding="branchOption"> - <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <selected value="true"/> - <text value="&Branch"/> - </properties> - </component> - <component id="653f0" class="javax.swing.JRadioButton" binding="tagOption"> - <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="&Tag"/> - </properties> - </component> - <component id="cefd6" class="javax.swing.JComboBox" binding="branchSelector"> - <constraints> - <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <enabled value="true"/> - <font name="Monospaced"/> - </properties> - </component> - <component id="e6ad1" class="javax.swing.JComboBox" binding="tagSelector"> - <constraints> - <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <enabled value="false"/> - <font name="Monospaced"/> - </properties> - </component> - <hspacer id="2892f"> - <constraints> - <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - </hspacer> - <component id="f1e00" class="javax.swing.JTextField" binding="revisionTxt"> - <constraints> - <grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> - <preferred-size width="150" height="-1"/> - </grid> - </constraints> - <properties> - <enabled value="false"/> - </properties> - </component> - <component id="f198c" class="javax.swing.JRadioButton" binding="revisionOption"> - <constraints> - <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <selected value="false"/> - <text value="&Revision"/> - </properties> - </component> - <component id="8ad2b" class="javax.swing.JRadioButton" binding="otherHeadRadioButton" default-binding="true"> - <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <selected value="false"/> - <text value="&Other head:"/> - <toolTipText value="There is exactly one other head on this branch"/> - </properties> - </component> - <component id="10618" class="javax.swing.JLabel" binding="otherHeadLabel"> - <constraints> - <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value=""/> - </properties> - </component> - <component id="dc07f" class="javax.swing.JRadioButton" binding="bookmarkOption"> - <constraints> - <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Book&mark"/> - </properties> - </component> - <component id="14e6b" class="javax.swing.JComboBox" binding="bookmarkSelector"> - <constraints> - <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <enabled value="false"/> - <font name="Monospaced"/> - </properties> - </component> - </children> - </grid> - <vspacer id="fe9e6"> - <constraints> - <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> - </constraints> - </vspacer> - <nested-form id="8b57e" form-file="org/zmlx/hg4idea/ui/HgRepositorySelectorComponent.form" binding="hgRepositorySelectorComponent"> - <constraints> - <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - </nested-form> - </children> - </grid> - <buttonGroups> - <group name="mergeTarget"> - <member id="f198c"/> - <member id="99075"/> - <member id="653f0"/> - <member id="8ad2b"/> - <member id="dc07f"/> - </group> - </buttonGroups> -</form> diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMergeDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMergeDialog.java index f41972a47cea..259fe1192c3b 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMergeDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMergeDialog.java @@ -12,181 +12,27 @@ // limitations under the License. package org.zmlx.hg4idea.ui; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ui.UIUtil; +import com.intellij.ui.IdeBorderFactory; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.command.HgHeadsCommand; -import org.zmlx.hg4idea.command.HgTagBranch; -import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; -import org.zmlx.hg4idea.util.HgBranchesAndTags; -import org.zmlx.hg4idea.util.HgUiUtil; +import org.zmlx.hg4idea.repo.HgRepository; -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -public class HgMergeDialog extends DialogWrapper { +public class HgMergeDialog extends HgCommonDialogWithChoices { - private final Project project; - - private JRadioButton revisionOption; - private JTextField revisionTxt; - private JRadioButton branchOption; - private JRadioButton tagOption; - private JRadioButton bookmarkOption; - private JComboBox branchSelector; - private JComboBox tagSelector; - private JComboBox bookmarkSelector; - private JPanel contentPanel; - private HgRepositorySelectorComponent hgRepositorySelectorComponent; - private JRadioButton otherHeadRadioButton; - private JLabel otherHeadLabel; - - private HgRevisionNumber otherHead; - private Map<VirtualFile, Collection<HgTagBranch>> branchesForRepos; - private Map<VirtualFile, Collection<HgTagBranch>> tagsForRepos; - private Map<VirtualFile, Collection<HgTagBranch>> bookmarksForRepos; - - public HgMergeDialog(Project project, - Collection<VirtualFile> roots, - @Nullable VirtualFile selectedRepo, HgBranchesAndTags branchesAndTags) { - super(project, false); - this.project = project; - branchesForRepos = branchesAndTags.getBranchesForRepos(); - tagsForRepos = branchesAndTags.getTagsForRepos(); - bookmarksForRepos = branchesAndTags.getBookmarksForRepos(); - setRoots(roots, selectedRepo); + public HgMergeDialog(@NotNull Project project, + @NotNull Collection<HgRepository> repositories, + @Nullable HgRepository selectedRepo) { + super(project, repositories, selectedRepo); hgRepositorySelectorComponent.setTitle("Select repository to merge"); - hgRepositorySelectorComponent.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - updateRepository(); - } - }); - - ChangeListener changeListener = new ChangeListener() { - public void stateChanged(ChangeEvent e) { - updateOptions(); - } - }; - branchOption.addChangeListener(changeListener); - tagOption.addChangeListener(changeListener); - bookmarkOption.addChangeListener(changeListener); - revisionOption.addChangeListener(changeListener); - otherHeadRadioButton.addChangeListener(changeListener); + myBranchesBorderPanel.setBorder(IdeBorderFactory.createTitledBorder("Merge with", true)); setTitle("Merge"); - init(); - } - - public void setRoots(Collection<VirtualFile> repos, @Nullable VirtualFile selectedRepo) { - hgRepositorySelectorComponent.setRoots(repos); - hgRepositorySelectorComponent.setSelectedRoot(selectedRepo); - updateRepository(); - } - - public VirtualFile getRepository() { - return hgRepositorySelectorComponent.getRepository(); - } - - public HgTagBranch getBranch() { - return branchOption.isSelected() ? (HgTagBranch) branchSelector.getSelectedItem() : null; - } - - public HgTagBranch getTag() { - return tagOption.isSelected() ? (HgTagBranch) tagSelector.getSelectedItem() : null; - } - - public HgTagBranch getBookmark() { - return bookmarkOption.isSelected() ? (HgTagBranch)bookmarkSelector.getSelectedItem() : null; - } - - public String getRevision() { - return revisionOption.isSelected() ? revisionTxt.getText() : null; - } - - public HgRevisionNumber getOtherHead() { - return otherHeadRadioButton.isSelected() ? otherHead : null; - } - - private void updateRepository() { - VirtualFile repo = getRepository(); - HgUiUtil.loadContentToDialog(repo, branchesForRepos, branchSelector); - HgUiUtil.loadContentToDialog(repo, tagsForRepos, tagSelector); - HgUiUtil.loadContentToDialog(repo, bookmarksForRepos, bookmarkSelector); - loadHeads(repo); - } - - private void updateOptions() { - revisionTxt.setEnabled(revisionOption.isSelected()); - branchSelector.setEnabled(branchOption.isSelected()); - tagSelector.setEnabled(tagOption.isSelected()); - bookmarkSelector.setEnabled(bookmarkOption.isSelected()); - } - - private void loadHeads(final VirtualFile root) { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - final List<HgRevisionNumber> heads = new HgHeadsCommand(project, root).execute(); - if (heads.size() != 2) { - disableOtherHeadsChoice(); - return; - } - - HgRevisionNumber currentParent = new HgWorkingCopyRevisionsCommand(project).identify(root).getFirst(); - for (Iterator<HgRevisionNumber> it = heads.iterator(); it.hasNext(); ) { - final HgRevisionNumber rev = it.next(); - if (rev.getRevisionNumber().equals(currentParent.getRevisionNumber())) { - it.remove(); - } - } - - if (heads.size() == 1) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - otherHeadRadioButton.setVisible(true); - otherHeadLabel.setVisible(true); - otherHead = heads.get(0); - otherHeadLabel.setText(" " + otherHead.asString()); - } - }); - } - else { - //apparently we are not at one of the heads - disableOtherHeadsChoice(); - } - } - }); - } - - private void disableOtherHeadsChoice() { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - otherHeadLabel.setVisible(false); - otherHeadRadioButton.setVisible(false); - } - }); - } - - @Nullable - @Override - protected JComponent createCenterPanel() { - return contentPanel; } @Override - protected String getDimensionServiceKey() { - return getClass().getName(); + protected String getHelpId() { + return "reference.mercurial.merge.dialog"; } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPullDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPullDialog.java index 5b4af4a5ba96..2729817a404e 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPullDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPullDialog.java @@ -23,8 +23,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorComboBox; import com.intellij.util.ArrayUtil; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgRememberedInputs; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.util.HgUtil; import javax.swing.*; @@ -40,7 +42,7 @@ public class HgPullDialog extends DialogWrapper { private EditorComboBox myRepositoryURL; private String myCurrentRepositoryUrl; - public HgPullDialog(Project project) { + public HgPullDialog(@NotNull Project project, @NotNull Collection<HgRepository> repositories, @Nullable final HgRepository selectedRepo) { super(project, false); this.project = project; hgRepositorySelector.setTitle("Select repository to pull changesets for"); @@ -53,6 +55,7 @@ public class HgPullDialog extends DialogWrapper { setTitle("Pull"); setOKButtonText("Pull"); init(); + setRoots(repositories, selectedRepo); } public void createUIComponents() { @@ -67,7 +70,7 @@ public class HgPullDialog extends DialogWrapper { }); } - private void addPathsFromHgrc(VirtualFile repo) { + private void addPathsFromHgrc(@NotNull VirtualFile repo) { Collection<String> paths = HgUtil.getRepositoryPaths(project, repo); for (String path : paths) { myRepositoryURL.prependItem(path); @@ -80,15 +83,15 @@ public class HgPullDialog extends DialogWrapper { } public VirtualFile getRepository() { - return hgRepositorySelector.getRepository(); + return hgRepositorySelector.getRepository().getRoot(); } public String getSource() { return myCurrentRepositoryUrl; } - public void setRoots(Collection<VirtualFile> repos, @Nullable final VirtualFile selectedRepo) { - hgRepositorySelector.setRoots(repos); + private void setRoots(@NotNull Collection<HgRepository> repositories, @Nullable final HgRepository selectedRepo) { + hgRepositorySelector.setRoots(repositories); hgRepositorySelector.setSelectedRoot(selectedRepo); onChangeRepository(); } @@ -106,8 +109,8 @@ public class HgPullDialog extends DialogWrapper { ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - final VirtualFile repo = hgRepositorySelector.getRepository(); - final String defaultPath = HgUtil.getRepositoryDefaultPath(project,repo); + final VirtualFile repo = hgRepositorySelector.getRepository().getRoot(); + final String defaultPath = HgUtil.getRepositoryDefaultPath(project, repo); if (!StringUtil.isEmptyOrSpaces(defaultPath)) { UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override @@ -133,5 +136,4 @@ public class HgPullDialog extends DialogWrapper { protected String getDimensionServiceKey() { return HgPullDialog.class.getName(); } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.form b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.form index a11d251812ad..ab1fd73801f5 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.form +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.form @@ -3,7 +3,7 @@ <grid id="27dc6" binding="contentPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="529" height="307"/> + <xy x="3" y="20" width="546" height="397"/> </constraints> <properties/> <border type="none"/> @@ -18,13 +18,13 @@ <children> <vspacer id="f51de"> <constraints> - <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="2" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> </vspacer> - <grid id="3b42" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="3b42" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"> + <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"> <minimum-size width="-1" height="100"/> </grid> </constraints> @@ -34,17 +34,9 @@ </clientProperties> <border type="etched" title="Options"/> <children> - <component id="e40ef" class="javax.swing.JCheckBox" binding="revisionCbx"> - <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="&Revision:"/> - </properties> - </component> <component id="8b024" class="javax.swing.JTextField" binding="revisionTxt"> <constraints> - <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <grid row="0" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> @@ -55,45 +47,76 @@ </component> <hspacer id="27a66"> <constraints> - <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="1" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> </hspacer> - <component id="5fcc4" class="javax.swing.JCheckBox" binding="forceCheckBox" default-binding="true"> + <grid id="3c96d" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> - <properties> - <text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.push.force"/> - </properties> - </component> - <component id="e6341" class="javax.swing.JCheckBox" binding="branchCheckBox" default-binding="true"> + <properties/> + <border type="etched" title="Branch Options"/> + <children> + <component id="1adc4" class="javax.swing.JComboBox" binding="branchComboBox"> + <constraints> + <grid row="0" column="1" row-span="1" col-span="2" vsize-policy="4" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + </component> + <component id="e6341" class="javax.swing.JCheckBox" binding="branchCheckBox" default-binding="true"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.push.branch"/> + </properties> + </component> + <component id="e76b" class="javax.swing.JCheckBox" binding="newBranchCheckBox"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <enabled value="false"/> + <horizontalAlignment value="0"/> + <horizontalTextPosition value="11"/> + <text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.push.asNewBranch"/> + </properties> + </component> + <component id="131ed" class="javax.swing.JComboBox" binding="myBookmarkComboBox"> + <constraints> + <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="4" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <editable value="true"/> + </properties> + </component> + <component id="a621e" class="javax.swing.JCheckBox" binding="myBookmarkCheckBox"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.push.bookmark"/> + </properties> + </component> + </children> + </grid> + <component id="e40ef" class="javax.swing.JCheckBox" binding="revisionCbx"> <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> - <text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.push.branch"/> + <text value="&Revision:"/> </properties> </component> - <component id="1adc4" class="javax.swing.JComboBox" binding="branchComboBox"> - <constraints> - <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties/> - </component> - <component id="e76b" class="javax.swing.JCheckBox" binding="newBranchCheckBox"> + <component id="5fcc4" class="javax.swing.JCheckBox" binding="forceCheckBox" default-binding="true"> <constraints> <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> - <enabled value="false"/> - <text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.push.asNewBranch"/> + <text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.push.force"/> </properties> </component> - <hspacer id="af930"> - <constraints> - <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> - </constraints> - </hspacer> </children> </grid> <nested-form id="9e17d" form-file="org/zmlx/hg4idea/ui/HgRepositorySelectorComponent.form" binding="hgRepositorySelectorComponent"> diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.java index 7660494463ec..892bbb933a06 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgPushDialog.java @@ -13,8 +13,6 @@ package org.zmlx.hg4idea.ui; import com.intellij.dvcs.DvcsRememberedInputs; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -24,10 +22,9 @@ import com.intellij.ui.EditorComboBox; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgPusher; import org.zmlx.hg4idea.HgRememberedInputs; import org.zmlx.hg4idea.HgVcsMessages; -import org.zmlx.hg4idea.command.HgTagBranch; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.util.HgUtil; import javax.swing.*; @@ -38,7 +35,6 @@ import javax.swing.event.DocumentListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; -import java.util.List; public class HgPushDialog extends DialogWrapper { @@ -53,9 +49,11 @@ public class HgPushDialog extends DialogWrapper { private JComboBox branchComboBox; private EditorComboBox myRepositoryURL; private JCheckBox newBranchCheckBox; + private JComboBox myBookmarkComboBox; + private JCheckBox myBookmarkCheckBox; private String myCurrentRepositoryUrl; - public HgPushDialog(Project project, Collection<VirtualFile> repos, List<HgTagBranch> branches, @Nullable VirtualFile selectedRepo) { + public HgPushDialog(Project project, Collection<HgRepository> repos, @Nullable HgRepository selectedRepo) { super(project, false); myProject = project; @@ -69,15 +67,22 @@ public class HgPushDialog extends DialogWrapper { final UpdatingListener updatingListener = new UpdatingListener(); revisionCbx.addChangeListener(updatingListener); branchCheckBox.addChangeListener(updatingListener); + myBookmarkCheckBox.addChangeListener(updatingListener); revisionTxt.getDocument().addDocumentListener(updatingListener); setTitle(HgVcsMessages.message("hg4idea.push.dialog.title")); setOKButtonText("Push"); init(); + setRoots(repos, selectedRepo); + } + + private void setRoots(@NotNull Collection<HgRepository> repos, + @Nullable HgRepository selectedRepo) { hgRepositorySelectorComponent.setRoots(repos); hgRepositorySelectorComponent.setSelectedRoot(selectedRepo); - updateBranchComboBox(branches); + HgRepository repo = hgRepositorySelectorComponent.getRepository(); + updateComboBoxes(repo); updateRepository(); } @@ -101,10 +106,12 @@ public class HgPushDialog extends DialogWrapper { } } - public VirtualFile getRepository() { + @NotNull + public HgRepository getRepository() { return hgRepositorySelectorComponent.getRepository(); } + @NotNull public String getTarget() { return myCurrentRepositoryUrl; } @@ -115,8 +122,13 @@ public class HgPushDialog extends DialogWrapper { } @Nullable - public HgTagBranch getBranch() { - return branchCheckBox.isSelected() ? (HgTagBranch) branchComboBox.getSelectedItem() : null; + public String getBranch() { + return branchCheckBox.isSelected() ? (String)branchComboBox.getSelectedItem() : null; + } + + @Nullable + public String getBookmarkName() { + return myBookmarkCheckBox.isSelected() ? (String)myBookmarkComboBox.getSelectedItem() : null; } public boolean isForce() { @@ -124,8 +136,8 @@ public class HgPushDialog extends DialogWrapper { } public boolean isNewBranch() { - return newBranchCheckBox.isSelected(); - } + return newBranchCheckBox.isSelected(); + } protected JComponent createCenterPanel() { return contentPanel; @@ -137,25 +149,21 @@ public class HgPushDialog extends DialogWrapper { } public void updateRepository() { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - final VirtualFile repo = hgRepositorySelectorComponent.getRepository(); - final String defaultPath = HgUtil.getRepositoryDefaultPushPath(myProject, repo); - final List<HgTagBranch> branches = HgPusher.getBranches(myProject, repo); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - addPathsFromHgrc(repo); - if (defaultPath != null) { - updateRepositoryUrlText(HgUtil.removePasswordIfNeeded(defaultPath)); - myCurrentRepositoryUrl = defaultPath; - } - updateBranchComboBox(branches); - } - }, ModalityState.stateForComponent(getRootPane())); - } - }); + HgRepository repo = hgRepositorySelectorComponent.getRepository(); + String defaultPath = HgUtil.getRepositoryDefaultPushPath(repo); + addPathsFromHgrc(repo.getRoot()); + if (defaultPath != null) { + updateRepositoryUrlText(HgUtil.removePasswordIfNeeded(defaultPath)); + myCurrentRepositoryUrl = defaultPath; + } + updateComboBoxes(repo); + } + + private void updateComboBoxes(HgRepository repo) { + final Collection<String> branches = repo.getOpenedBranches(); + final Collection<String> bookmarkNames = HgUtil.getNamesWithoutHashes(repo.getBookmarks()); + branchComboBox.setModel(new DefaultComboBoxModel(branches.toArray())); + myBookmarkComboBox.setModel(new DefaultComboBoxModel(bookmarkNames.toArray())); } private void updateRepositoryUrlText(String defaultPath) { @@ -165,15 +173,12 @@ public class HgPushDialog extends DialogWrapper { } } - private void updateBranchComboBox(@NotNull List<HgTagBranch> branches) { - branchComboBox.setModel(new DefaultComboBoxModel(branches.toArray())); - } - private void update() { setOKActionEnabled(validateOptions()); revisionTxt.setEnabled(revisionCbx.isSelected()); branchComboBox.setEnabled(branchCheckBox.isSelected()); newBranchCheckBox.setEnabled(branchCheckBox.isSelected()); + myBookmarkComboBox.setEnabled(myBookmarkCheckBox.isSelected()); } private boolean validateOptions() { @@ -213,5 +218,4 @@ public class HgPushDialog extends DialogWrapper { update(); } } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgRepositorySelectorComponent.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgRepositorySelectorComponent.java index 89fc834de60b..edc2fb0c1dec 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgRepositorySelectorComponent.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgRepositorySelectorComponent.java @@ -12,10 +12,10 @@ // limitations under the License. package org.zmlx.hg4idea.ui; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.IdeBorderFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.repo.HgRepository; import javax.swing.*; import java.awt.event.ActionListener; @@ -25,54 +25,31 @@ public class HgRepositorySelectorComponent { private JComboBox repositorySelector; private JPanel mainPanel; - public void setRoots(Collection<VirtualFile> roots) { + public void setRoots(Collection<HgRepository> roots) { DefaultComboBoxModel model = new DefaultComboBoxModel(); - for (VirtualFile repo : roots) { - model.addElement(new RepositoryDisplay(repo)); + for (HgRepository repo : roots) { + model.addElement(repo); } repositorySelector.setModel(model); mainPanel.setVisible(roots.size() > 1); } - public void setSelectedRoot(@Nullable VirtualFile repository) { + public void setSelectedRoot(@Nullable HgRepository repository) { if (repository != null) { - repositorySelector.setSelectedItem(new RepositoryDisplay(repository)); + repositorySelector.setSelectedItem(repository); } } - public void addActionListener(ActionListener actionListener) { + public void addActionListener(@NotNull ActionListener actionListener) { repositorySelector.addActionListener(actionListener); } - public void setTitle(String title) { + public void setTitle(@NotNull String title) { mainPanel.setBorder(IdeBorderFactory.createTitledBorder(title, true)); } - public VirtualFile getRepository() { - return ((RepositoryDisplay) repositorySelector.getSelectedItem()).repo; + @NotNull + public HgRepository getRepository() { + return (HgRepository)repositorySelector.getSelectedItem(); } - - private class RepositoryDisplay { - @NotNull private final VirtualFile repo; - - public RepositoryDisplay(@NotNull VirtualFile repo) { - this.repo = repo; - } - - @Override - public String toString() { - return repo.getPresentableUrl(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof RepositoryDisplay && this.repo.equals(((RepositoryDisplay)obj).repo); - } - - @Override - public int hashCode() { - return repo.hashCode(); - } - } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgRunConflictResolverDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgRunConflictResolverDialog.java index ca4ab00462f6..0196bd4a16cc 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgRunConflictResolverDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgRunConflictResolverDialog.java @@ -18,10 +18,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.command.HgResolveCommand; import org.zmlx.hg4idea.command.HgResolveStatusEnum; +import org.zmlx.hg4idea.repo.HgRepository; import javax.swing.*; import java.awt.event.ActionEvent; @@ -37,7 +39,9 @@ public class HgRunConflictResolverDialog extends DialogWrapper { private final Project project; - public HgRunConflictResolverDialog(Project project) { + public HgRunConflictResolverDialog(@NotNull Project project, + @NotNull Collection<HgRepository> repositories, + @Nullable HgRepository selectedRepo) { super(project, false); this.project = project; repositorySelector.addActionListener(new ActionListener() { @@ -47,14 +51,16 @@ public class HgRunConflictResolverDialog extends DialogWrapper { }); setTitle("Resolve Conflicts"); init(); + setRoots(repositories, selectedRepo); } - public VirtualFile getRepository() { + @NotNull + public HgRepository getRepository() { return repositorySelector.getRepository(); } - public void setRoots(Collection<VirtualFile> repos, @Nullable VirtualFile selectedRepo) { - repositorySelector.setRoots(repos); + private void setRoots(@NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) { + repositorySelector.setRoots(repositories); repositorySelector.setSelectedRoot(selectedRepo); onChangeRepository(); } @@ -64,7 +70,7 @@ public class HgRunConflictResolverDialog extends DialogWrapper { } private void onChangeRepository() { - VirtualFile repo = repositorySelector.getRepository(); + VirtualFile repo = repositorySelector.getRepository().getRoot(); HgResolveCommand command = new HgResolveCommand(project); final ModalityState modalityState = ApplicationManager.getApplication().getModalityStateForComponent(getRootPane()); command.list(repo, new Consumer<Map<HgFile, HgResolveStatusEnum>>() { @@ -90,5 +96,4 @@ public class HgRunConflictResolverDialog extends DialogWrapper { } }); } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgTagDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgTagDialog.java index 02e3e8d7a245..ba900078600a 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgTagDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgTagDialog.java @@ -16,7 +16,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.repo.HgRepository; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -29,7 +31,7 @@ public class HgTagDialog extends DialogWrapper { private JTextField tagTxt; private HgRepositorySelectorComponent hgRepositorySelectorComponent; - public HgTagDialog(Project project) { + public HgTagDialog(@NotNull Project project, @NotNull Collection<HgRepository> repos, @Nullable HgRepository selectedRepo) { super(project, false); hgRepositorySelectorComponent.setTitle("Select repository to tag"); DocumentListener documentListener = new DocumentListener() { @@ -50,6 +52,8 @@ public class HgTagDialog extends DialogWrapper { setTitle("Tag"); init(); + + setRoots(repos, selectedRepo); } public String getTagName() { @@ -57,10 +61,10 @@ public class HgTagDialog extends DialogWrapper { } public VirtualFile getRepository() { - return hgRepositorySelectorComponent.getRepository(); + return hgRepositorySelectorComponent.getRepository().getRoot(); } - public void setRoots(Collection<VirtualFile> repos, @Nullable VirtualFile selectedRepo) { + private void setRoots(@NotNull Collection<HgRepository> repos, @Nullable HgRepository selectedRepo) { hgRepositorySelectorComponent.setRoots(repos); hgRepositorySelectorComponent.setSelectedRoot(selectedRepo); update(); @@ -77,5 +81,4 @@ public class HgTagDialog extends DialogWrapper { private boolean validateOptions() { return !StringUtil.isEmptyOrSpaces(tagTxt.getText()); } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgUpdateToDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgUpdateToDialog.java index d6638dde80b4..c0b66075841b 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgUpdateToDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgUpdateToDialog.java @@ -13,141 +13,30 @@ package org.zmlx.hg4idea.ui; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.IdeBorderFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.command.HgTagBranch; -import org.zmlx.hg4idea.util.HgBranchesAndTags; -import org.zmlx.hg4idea.util.HgUiUtil; +import org.zmlx.hg4idea.repo.HgRepository; -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.Collection; -import java.util.Map; -public class HgUpdateToDialog extends DialogWrapper { +public class HgUpdateToDialog extends HgCommonDialogWithChoices { - private final Project project; - - private JPanel contentPanel; - private JRadioButton branchOption; - private JRadioButton revisionOption; - private JRadioButton tagOption; - private JRadioButton bookmarkOption; - private JTextField revisionTxt; - private JCheckBox cleanCbx; - private JComboBox branchSelector; - private JComboBox tagSelector; - private JComboBox bookmarkSelector; - private HgRepositorySelectorComponent hgRepositorySelectorComponent; - @NotNull private Map<VirtualFile, Collection<HgTagBranch>> branchesForRepos; - @NotNull private Map<VirtualFile, Collection<HgTagBranch>> tagsForRepos; - @NotNull private Map<VirtualFile, Collection<HgTagBranch>> bookmarksForRepos; - - public HgUpdateToDialog(Project project) { - super(project, false); - this.project = project; + public HgUpdateToDialog(Project project, @NotNull Collection<HgRepository> repos, @Nullable HgRepository selectedRepo) { + super(project, repos, selectedRepo); + myBranchesBorderPanel.setBorder(IdeBorderFactory.createTitledBorder("Switch to", true)); hgRepositorySelectorComponent.setTitle("Select repository to switch"); - hgRepositorySelectorComponent.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - updateRepository(); - } - }); - - ChangeListener changeListener = new ChangeListener() { - public void stateChanged(ChangeEvent e) { - update(); - } - }; - branchOption.addChangeListener(changeListener); - tagOption.addChangeListener(changeListener); - bookmarkOption.addChangeListener(changeListener); - revisionOption.addChangeListener(changeListener); - - setTitle("Switch working directory"); - init(); - } - - public void setRoots(Collection<VirtualFile> repos, - @Nullable VirtualFile selectedRepo, HgBranchesAndTags branchesAndTags) { - hgRepositorySelectorComponent.setRoots(repos); - branchesForRepos = branchesAndTags.getBranchesForRepos(); - tagsForRepos = branchesAndTags.getTagsForRepos(); - bookmarksForRepos = branchesAndTags.getBookmarksForRepos(); - hgRepositorySelectorComponent.setSelectedRoot(selectedRepo); - updateRepository(); - } - - public VirtualFile getRepository() { - return hgRepositorySelectorComponent.getRepository(); - } - - public HgTagBranch getTag() { - return (HgTagBranch) tagSelector.getSelectedItem(); - } - - public boolean isTagSelected() { - return tagOption.isSelected(); - } - - public HgTagBranch getBranch() { - return (HgTagBranch) branchSelector.getSelectedItem(); - } - - public boolean isBranchSelected() { - return branchOption.isSelected(); - } - - public HgTagBranch getBookmark() { - return (HgTagBranch)bookmarkSelector.getSelectedItem(); - } - - public boolean isBookmarkSelected() { - return bookmarkOption.isSelected(); - } - - public String getRevision() { - return revisionTxt.getText(); - } - - public boolean isRevisionSelected() { - return revisionOption.isSelected(); + setTitle("Switch Working Directory"); + cleanCbx.setVisible(true); + cleanCbx.setEnabled(true); } public boolean isRemoveLocalChanges() { return cleanCbx.isSelected(); } - private void update() { - revisionTxt.setEnabled(revisionOption.isSelected()); - branchSelector.setEnabled(branchOption.isSelected()); - tagSelector.setEnabled(tagOption.isSelected()); - bookmarkSelector.setEnabled(bookmarkOption.isSelected()); - } - - private void updateRepository() { - VirtualFile repo = hgRepositorySelectorComponent.getRepository(); - HgUiUtil.loadContentToDialog(repo, branchesForRepos, branchSelector); - HgUiUtil.loadContentToDialog(repo, tagsForRepos, tagSelector); - HgUiUtil.loadContentToDialog(repo, bookmarksForRepos, bookmarkSelector); - update(); - } - - protected JComponent createCenterPanel() { - return contentPanel; - } - @Override protected String getHelpId() { return "reference.mercurial.switch.working.directory"; } - - @Override - protected String getDimensionServiceKey() { - return getClass().getName(); - } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgBranchesAndTags.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgBranchesAndTags.java deleted file mode 100644 index 08d71414594b..000000000000 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgBranchesAndTags.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.zmlx.hg4idea.util; - -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.zmlx.hg4idea.command.HgTagBranch; - -import java.util.Collection; -import java.util.Map; - -/** - * @author Nadya Zabrodina - */ - -public class HgBranchesAndTags { - - @NotNull private final Map<VirtualFile, Collection<HgTagBranch>> branchesForRepos = ContainerUtil.newHashMap(); - @NotNull private final Map<VirtualFile, Collection<HgTagBranch>> tagsForRepos = ContainerUtil.newHashMap(); - @NotNull private final Map<VirtualFile, Collection<HgTagBranch>> bookmarks = ContainerUtil.newHashMap(); - - @NotNull - public Map<VirtualFile, Collection<HgTagBranch>> getBranchesForRepos() { - return branchesForRepos; - } - - public void addBranches(@NotNull VirtualFile repo, @NotNull Collection<HgTagBranch> branches) { - branchesForRepos.put(repo, branches); - } - - @NotNull - public Map<VirtualFile, Collection<HgTagBranch>> getTagsForRepos() { - return tagsForRepos; - } - - public void addTags(@NotNull VirtualFile repo, @NotNull Collection<HgTagBranch> tags) { - tagsForRepos.put(repo, tags); - } - - @NotNull - public Map<VirtualFile, Collection<HgTagBranch>> getBookmarksForRepos() { - return bookmarks; - } - - public void addBookmarks(@NotNull VirtualFile repo, @NotNull Collection<HgTagBranch> tags) { - bookmarks.put(repo, tags); - } -}
\ No newline at end of file diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUiUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUiUtil.java deleted file mode 100644 index 6d806b309ed0..000000000000 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUiUtil.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.zmlx.hg4idea.util; - -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.Task; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgVcsMessages; -import org.zmlx.hg4idea.action.HgCommandResultNotifier; -import org.zmlx.hg4idea.command.HgTagBranch; -import org.zmlx.hg4idea.command.HgTagBranchCommand; -import org.zmlx.hg4idea.execution.HgCommandResult; - -import javax.swing.*; -import java.util.Collection; -import java.util.Map; - -/** - * @author Nadya Zabrodina - */ -public class HgUiUtil { - - public static void loadBranchesInBackgroundableAndExecuteAction(@NotNull final Project project, - @NotNull final Collection<VirtualFile> repos, - @NotNull final Consumer<HgBranchesAndTags> successHandler) { - final HgBranchesAndTags branchTagInfo = new HgBranchesAndTags(); - new Task.Backgroundable(project, "Collecting information...") { - @Override - public void run(@NotNull ProgressIndicator indicator) { - for (final VirtualFile repo : repos) { - HgTagBranchCommand tagBranchCommand = new HgTagBranchCommand(project, repo); - HgCommandResult result = tagBranchCommand.collectBranches(); - if (result == null) { - indicator.cancel(); - return; - } - branchTagInfo.addBranches(repo, HgTagBranchCommand.parseResult(result)); - result = tagBranchCommand.collectTags(); - if (result == null) { - indicator.cancel(); - return; - } - branchTagInfo.addTags(repo, HgTagBranchCommand.parseResult(result)); - - result = tagBranchCommand.collectBookmarks(); - if (result == null) { - indicator.cancel(); - return; - } - branchTagInfo.addBookmarks(repo, HgTagBranchCommand.parseResult(result)); - } - } - - @Override - public void onCancel() { - new HgCommandResultNotifier(project) - .notifyError(null, "Mercurial command failed", HgVcsMessages.message("hg4idea.branches.error.description")); - } - - @Override - public void onSuccess() { - successHandler.consume(branchTagInfo); - } - }.queue(); - } - - public static void loadContentToDialog(@Nullable VirtualFile root, @NotNull Map<VirtualFile, Collection<HgTagBranch>> contentMap, - @NotNull JComboBox selector) { - assert contentMap.get(root) != null : "No information about root " + root; - selector.setModel(new DefaultComboBoxModel(contentMap.get(root).toArray())); - } -} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java index fd0fc503df7d..ee7f1b4f5ce4 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java @@ -40,6 +40,7 @@ import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.impl.status.StatusBarUtil; import com.intellij.ui.GuiUtils; +import com.intellij.util.containers.ContainerUtil; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -241,6 +242,21 @@ public abstract class HgUtil { } /** + * Get hg roots for paths + * + * @param filePaths the context paths + * @return a set of hg roots + */ + @NotNull + public static Set<VirtualFile> hgRoots(@NotNull Project project, @NotNull Collection<FilePath> filePaths) { + HashSet<VirtualFile> roots = new HashSet<VirtualFile>(); + for (FilePath path : filePaths) { + ContainerUtil.addIfNotNull(roots, getHgRootOrNull(project, path)); + } + return roots; + } + + /** * Gets the Mercurial root for the given file path or null if non exists: * the root should not only be in directory mappings, but also the .hg repository folder should exist. * @see #getHgRootOrThrow(com.intellij.openapi.project.Project, com.intellij.openapi.vcs.FilePath) @@ -596,6 +612,11 @@ public abstract class HgUtil { } @Nullable + public static String getRepositoryDefaultPushPath(@NotNull HgRepository repository) { + return repository.getRepositoryConfig().getDefaultPushPath(); + } + + @Nullable public static String getConfig(@NotNull Project project, @NotNull VirtualFile root, @NotNull String section, @@ -646,6 +667,7 @@ public abstract class HgUtil { names.add(hash.getName()); } } + Collections.sort(names); return names; } diff --git a/plugins/javaFX/FxBuilderEmbedder/FxBuilderEmbedder.iml b/plugins/javaFX/FxBuilderEmbedder/FxBuilderEmbedder.iml index 94b91b59e731..2a19b787b2f7 100644 --- a/plugins/javaFX/FxBuilderEmbedder/FxBuilderEmbedder.iml +++ b/plugins/javaFX/FxBuilderEmbedder/FxBuilderEmbedder.iml @@ -17,6 +17,7 @@ <SOURCES /> </library> </orderEntry> + <orderEntry type="module" module-name="javaFX" /> </component> </module> diff --git a/plugins/javaFX/FxBuilderEmbedder/lib/embedder.jar b/plugins/javaFX/FxBuilderEmbedder/lib/embedder.jar Binary files differindex 10561a4d95e1..e853e975c532 100644 --- a/plugins/javaFX/FxBuilderEmbedder/lib/embedder.jar +++ b/plugins/javaFX/FxBuilderEmbedder/lib/embedder.jar diff --git a/plugins/javaFX/FxBuilderEmbedder/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderImpl.java b/plugins/javaFX/FxBuilderEmbedder/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderImpl.java index 6748c0738622..65b15576c6a3 100644 --- a/plugins/javaFX/FxBuilderEmbedder/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderImpl.java +++ b/plugins/javaFX/FxBuilderEmbedder/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderImpl.java @@ -5,7 +5,10 @@ import com.oracle.javafx.scenebuilder.kit.editor.panel.content.ContentPanelContr import com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.treeview.HierarchyTreeViewController; import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController; import com.oracle.javafx.scenebuilder.kit.editor.panel.library.LibraryPanelController; -import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; +import com.oracle.javafx.scenebuilder.kit.editor.selection.AbstractSelectionGroup; +import com.oracle.javafx.scenebuilder.kit.editor.selection.ObjectSelectionGroup; +import com.oracle.javafx.scenebuilder.kit.fxom.*; +import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName; import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; @@ -17,6 +20,7 @@ import javafx.scene.control.SplitPane; import javax.swing.*; import java.net.URL; +import java.util.*; /** * @author Alexander Lobas @@ -26,8 +30,10 @@ public class SceneBuilderImpl implements SceneBuilder { private final EditorCallback myEditorCallback; private final JFXPanel myPanel = new JFXPanel(); private EditorController myEditorController; - private ChangeListener<Number> myListener; private volatile boolean mySkipChanges; + private ChangeListener<Number> myListener; + private ChangeListener<Number> mySelectionListener; + private final Map<String, int[][]> mySelectionState = new FixedHashMap<String, int[][]>(16); public SceneBuilderImpl(URL url, EditorCallback editorCallback) { myFileURL = url; @@ -80,7 +86,6 @@ public class SceneBuilderImpl implements SceneBuilder { Platform.runLater(new Runnable() { @Override public void run() { - // TODO: restore state loadFile(); } }); @@ -96,13 +101,26 @@ public class SceneBuilderImpl implements SceneBuilder { } } }; + mySelectionListener = new ChangeListener<Number>() { + @Override + public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { + if (!mySkipChanges) { + int[][] state = getSelectionState(); + if (state != null) { + mySelectionState.put(myEditorController.getFxmlText(), state); + } + } + } + }; myEditorController.getJobManager().revisionProperty().addListener(myListener); + myEditorController.getSelection().revisionProperty().addListener(mySelectionListener); } @Override public void close() { if (myEditorController != null) { + myEditorController.getSelection().revisionProperty().removeListener(mySelectionListener); myEditorController.getJobManager().revisionProperty().removeListener(myListener); } } @@ -113,6 +131,11 @@ public class SceneBuilderImpl implements SceneBuilder { try { String fxmlText = FXOMDocument.readContentFromURL(myFileURL); myEditorController.setFxmlTextAndLocation(fxmlText, myFileURL); + + int[][] selectionState = mySelectionState.get(fxmlText); + if (selectionState != null) { + restoreSelection(selectionState); + } } catch (Throwable e) { myEditorCallback.handleError(e); @@ -121,4 +144,133 @@ public class SceneBuilderImpl implements SceneBuilder { mySkipChanges = false; } } + + private int[][] getSelectionState() { + AbstractSelectionGroup group = myEditorController.getSelection().getGroup(); + if (group instanceof ObjectSelectionGroup) { + Set<FXOMObject> items = ((ObjectSelectionGroup)group).getItems(); + int[][] state = new int[items.size()][]; + int index = 0; + + for (FXOMObject item : items) { + IntArrayList path = new IntArrayList(); + componentToPath(item, path); + state[index++] = path.toArray(); + } + + return state; + } + + return null; + } + + private static void componentToPath(FXOMObject component, IntArrayList path) { + FXOMObject parent = component.getParentObject(); + + if (parent != null) { + path.add(0, component.getParentProperty().getValues().indexOf(component)); + componentToPath(parent, path); + } + } + + private void restoreSelection(int[][] state) { + Collection<FXOMObject> newSelection = new ArrayList<FXOMObject>(); + FXOMObject rootComponent = myEditorController.getFxomDocument().getFxomRoot(); + + for (int[] path : state) { + pathToComponent(newSelection, rootComponent, path, 0); + } + + myEditorController.getSelection().select(newSelection); + } + + private static void pathToComponent(Collection<FXOMObject> components, FXOMObject component, int[] path, int index) { + if (index == path.length) { + components.add(component); + } + else { + List<FXOMObject> children = Collections.emptyList(); + Map<PropertyName, FXOMProperty> properties = ((FXOMInstance)component).getProperties(); + for (Map.Entry<PropertyName, FXOMProperty> entry : properties.entrySet()) { + FXOMProperty value = entry.getValue(); + if (value instanceof FXOMPropertyC) { + children = ((FXOMPropertyC)value).getValues(); + break; + } + } + + int componentIndex = path[index]; + if (0 <= componentIndex && componentIndex < children.size()) { + pathToComponent(components, children.get(componentIndex), path, index + 1); + } + } + } + + private static class FixedHashMap<K, V> extends HashMap<K, V> { + private final int mySize; + private final List<K> myKeys = new LinkedList<K>(); + + public FixedHashMap(int size) { + mySize = size; + } + + @Override + public V put(K key, V value) { + if (!myKeys.contains(key)) { + if (myKeys.size() >= mySize) { + remove(myKeys.remove(0)); + } + myKeys.add(key); + } + return super.put(key, value); + } + + @Override + public V get(Object key) { + if (myKeys.contains(key)) { + int index = myKeys.indexOf(key); + int last = myKeys.size() - 1; + myKeys.set(index, myKeys.get(last)); + myKeys.set(last, (K)key); + } + return super.get(key); + } + } + + private static final int[] EMPTY_INTS = new int[0]; + + private static class IntArrayList { + private int[] myData = EMPTY_INTS; + private int mySize; + + public void add(int index, int element) { + if (index > mySize || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize); + } + + ensureCapacity(mySize + 1); + System.arraycopy(myData, index, myData, index + 1, mySize - index); + myData[index] = element; + mySize++; + } + + public void ensureCapacity(int minCapacity) { + int oldCapacity = myData.length; + if (minCapacity > oldCapacity) { + int[] oldData = myData; + int newCapacity = oldCapacity * 3 / 2 + 1; + if (newCapacity < minCapacity) { + newCapacity = minCapacity; + } + myData = new int[newCapacity]; + System.arraycopy(oldData, 0, myData, 0, mySize); + } + } + + public int[] toArray() { + int[] result = new int[mySize]; + System.arraycopy(myData, 0, result, 0, mySize); + return result; + } + } }
\ No newline at end of file diff --git a/plugins/javaFX/javaFX-CE/src/META-INF/plugin.xml b/plugins/javaFX/javaFX-CE/src/META-INF/plugin.xml index e0372107d51a..6b65da2e0774 100644 --- a/plugins/javaFX/javaFX-CE/src/META-INF/plugin.xml +++ b/plugins/javaFX/javaFX-CE/src/META-INF/plugin.xml @@ -4,7 +4,17 @@ <version>1.0</version> <vendor>JetBrains</vendor> <description> - This plugin provides JavaFX2 support. - </description> + <![CDATA[ + This plugin enables <a href="http://www.oracle.com/technetwork/java/javafx/overview/index.html">JavaFX</a> support. + The following features are available: + <ul> + <li>Dedicated file type.</li> + <li>Ability to create a project with the special file and directory structure.</li> + <li>JavaFX-aware coding assistance (code completion, search, navigation and refactoring in JavaFX-specific source files).</li> + <li>Integration with <a href="http://www.oracle.com/technetwork/java/javafx/tools/index.html">JavaFX Scene Builder</a>.</li> + <li>JavaFX application packaging capabilities.</li> + </ul> + ]]> + </description> <xi:include href="/META-INF/common-javaFX-plugin.xml" xpointer="xpointer(/idea-plugin/*)"/> </idea-plugin> diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/FxmlDataExternalizer.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/FxmlDataExternalizer.java index 2de1bc61d599..384d0859f82d 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/FxmlDataExternalizer.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/FxmlDataExternalizer.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.javaFX; import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; @@ -29,7 +30,7 @@ import java.util.Set; */ public class FxmlDataExternalizer implements DataExternalizer<Set<String>> { @Override - public void save(DataOutput out, Set<String> value) throws IOException { + public void save(@NotNull DataOutput out, Set<String> value) throws IOException { out.writeInt(value.size()); for (String s : value) { out.writeUTF(s); @@ -37,7 +38,7 @@ public class FxmlDataExternalizer implements DataExternalizer<Set<String>> { } @Override - public Set<String> read(DataInput in) throws IOException { + public Set<String> read(@NotNull DataInput in) throws IOException { final int size = in.readInt(); final Set<String> result = new HashSet<String>(size); diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxControllerClassIndex.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxControllerClassIndex.java index 1caf0a037fb3..e5c39157ae8e 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxControllerClassIndex.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxControllerClassIndex.java @@ -58,11 +58,13 @@ public class JavaFxControllerClassIndex extends ScalarIndexExtension<String> { return myDataIndexer; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; @@ -133,7 +135,7 @@ public class JavaFxControllerClassIndex extends ScalarIndexExtension<String> { super(StdFileTypes.XML); } @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return JavaFxFileTypeFactory.isFxml(file); } } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxCustomComponentsIndex.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxCustomComponentsIndex.java index 50c8b8493970..2178fd89a7d9 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxCustomComponentsIndex.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxCustomComponentsIndex.java @@ -81,11 +81,13 @@ public class JavaFxCustomComponentsIndex extends FileBasedIndexExtension<String, return myDataIndexer; } + @NotNull @Override public DataExternalizer<Set<String>> getValueExternalizer() { return myDataExternalizer; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; @@ -97,6 +99,7 @@ public class JavaFxCustomComponentsIndex extends FileBasedIndexExtension<String, return KEY; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxIdsIndex.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxIdsIndex.java index e0fe90a2ea79..fcaaada562ca 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxIdsIndex.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/JavaFxIdsIndex.java @@ -42,11 +42,13 @@ public class JavaFxIdsIndex extends FileBasedIndexExtension<String, Set<String>> return myDataIndexer; } + @NotNull @Override public DataExternalizer<Set<String>> getValueExternalizer() { return myDataExternalizer; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; @@ -58,6 +60,7 @@ public class JavaFxIdsIndex extends FileBasedIndexExtension<String, Set<String>> return KEY; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditorProvider.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditorProvider.java index de123d1ee1bb..6ea5c510ce4d 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditorProvider.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditorProvider.java @@ -27,7 +27,7 @@ public class SceneBuilderEditorProvider implements FileEditorProvider, DumbAware public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { return JavaFxFileTypeFactory.FXML_EXTENSION.equalsIgnoreCase(file.getExtension()) && SystemInfo.isJavaVersionAtLeast("1.8") && - Registry.is("embed.scene.builder", false); + Registry.is("embed.scene.builder", true); } @NotNull diff --git a/plugins/junit/src/META-INF/plugin.xml b/plugins/junit/src/META-INF/plugin.xml index d023807439dc..969fec8f58bc 100644 --- a/plugins/junit/src/META-INF/plugin.xml +++ b/plugins/junit/src/META-INF/plugin.xml @@ -16,7 +16,18 @@ <idea-plugin> <name>JUnit</name> - <description>Provides possibility to run JUnit 3.x and 4.x tests and view their results</description> + <description> + <![CDATA[ + This plugin supports <a href="https://github.com/junit-team/junit">JUnit tests</a>. + The following features are available: + <ul> + <li>Ability to create JUnit 3.x or JUnit 4.x tests.</li> + <li>Navigation between a test and test subject.</li> + <li>Running tests.</li> + <li>Viewing test results in the dedicated Test Runner tab of the Run tool window.</li> + </ul> + ]]> + </description> <version>1.0</version> <vendor>JetBrains</vendor> <extensions defaultExtensionNs="com.intellij"> diff --git a/plugins/maven/jps-plugin/maven-jps-plugin.iml b/plugins/maven/jps-plugin/maven-jps-plugin.iml index 8098c4c4d4ba..f601ed39bca5 100644 --- a/plugins/maven/jps-plugin/maven-jps-plugin.iml +++ b/plugins/maven/jps-plugin/maven-jps-plugin.iml @@ -22,6 +22,7 @@ <SOURCES /> </library> </orderEntry> + <orderEntry type="module" module-name="jps-serialization-tests" scope="TEST" /> </component> </module> diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java index 8fe4348a0ade..0c4be99814c1 100644 --- a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java @@ -29,7 +29,8 @@ public interface MavenServerEmbedder extends Remote { void customize(@Nullable MavenWorkspaceMap workspaceMap, boolean failOnUnresolvedDependency, @NotNull MavenServerConsole console, - @NotNull MavenServerProgressIndicator indicator) throws RemoteException; + @NotNull MavenServerProgressIndicator indicator, + boolean alwaysUpdateSnapshots) throws RemoteException; @NotNull MavenServerExecutionResult resolveProject(@NotNull File file, diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java index 630e664c2366..7ed82b0494dc 100644 --- a/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java @@ -586,7 +586,8 @@ public class Maven2ServerEmbedderImpl extends MavenRemoteObject implements Maven public void customize(@Nullable MavenWorkspaceMap workspaceMap, boolean failOnUnresolvedDependency, @NotNull MavenServerConsole console, - @NotNull MavenServerProgressIndicator indicator) { + @NotNull MavenServerProgressIndicator indicator, + boolean alwaysUpdateSnapshots) { try { ((CustomArtifactFactory)getComponent(ArtifactFactory.class)).customize(); ((CustomArtifactFactory)getComponent(ProjectArtifactFactory.class)).customize(); diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java index ae454210c909..ded8fa37a958 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java @@ -111,6 +111,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven private Date myBuildStartTime; + private boolean myAlwaysUpdateSnapshots; + public Maven3ServerEmbedderImpl(MavenServerSettings settings) throws RemoteException { File mavenHome = settings.getMavenHome(); if (mavenHome != null) { @@ -269,7 +271,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven public void customize(@Nullable MavenWorkspaceMap workspaceMap, boolean failOnUnresolvedDependency, @NotNull MavenServerConsole console, - @NotNull MavenServerProgressIndicator indicator) throws RemoteException { + @NotNull MavenServerProgressIndicator indicator, + boolean alwaysUpdateSnapshots) throws RemoteException { try { ((CustomMaven3ArtifactFactory)getComponent(ArtifactFactory.class)).customize(); @@ -281,6 +284,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven myBuildStartTime = new Date(); + myAlwaysUpdateSnapshots = alwaysUpdateSnapshots; + setConsoleAndIndicator(console, new MavenServerProgressIndicatorWrapper(indicator)); } catch (Exception e) { @@ -349,6 +354,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven final MavenExecutionRequest request = createRequest(file, activeProfiles, Collections.<String>emptyList(), Collections.<String>emptyList()); + request.setUpdateSnapshots(myAlwaysUpdateSnapshots); + final AtomicReference<MavenExecutionResult> ref = new AtomicReference<MavenExecutionResult>(); executeWithMavenSession(request, new Runnable() { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/generate/GenerateManagedDependencyAction.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/generate/GenerateManagedDependencyAction.java index 18250c395ee5..93af00a1e1e2 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/generate/GenerateManagedDependencyAction.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/generate/GenerateManagedDependencyAction.java @@ -78,10 +78,16 @@ public class GenerateManagedDependencyAction extends GenerateDomElementAction { dependency.getGroupId().setStringValue(groupId); dependency.getArtifactId().setStringValue(artifactId); String typeValue = parentDependency.getType().getStringValue(); + String classifier = parentDependency.getClassifier().getStringValue(); if (!StringUtil.isEmptyOrSpaces(typeValue)) { dependency.getType().setStringValue(typeValue); } + + if (!StringUtil.isEmptyOrSpaces(classifier)) { + dependency.getClassifier().setStringValue(classifier); + } + dependency.getVersion().undefine(); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java index 614332fcadd4..e80920890f48 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.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. @@ -666,14 +666,14 @@ public class MavenIndex { } private static class SetDescriptor implements DataExternalizer<Set<String>> { - public void save(DataOutput s, Set<String> set) throws IOException { + public void save(@NotNull DataOutput s, Set<String> set) throws IOException { s.writeInt(set.size()); for (String each : set) { s.writeUTF(each); } } - public Set<String> read(DataInput s) throws IOException { + public Set<String> read(@NotNull DataInput s) throws IOException { int count = s.readInt(); Set<String> result = new THashSet<String>(count); while (count-- > 0) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java index 4089981b1627..0019d59b3d7d 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java @@ -1206,7 +1206,7 @@ public class MavenProjectsTree { @NotNull ResolveContext context, @NotNull MavenProgressIndicator process) throws MavenProcessCanceledException { MavenEmbedderWrapper embedder = embeddersManager.getEmbedder(MavenEmbeddersManager.FOR_DEPENDENCIES_RESOLVE); - embedder.customizeForResolve(getWorkspaceMap(), console, process); + embedder.customizeForResolve(getWorkspaceMap(), console, process, generalSettings.isAlwaysUpdateSnapshots()); try { process.checkCanceled(); @@ -1321,7 +1321,7 @@ public class MavenProjectsTree { @NotNull MavenProgressIndicator process, @NotNull EmbedderTask task) throws MavenProcessCanceledException { MavenEmbedderWrapper embedder = embeddersManager.getEmbedder(embedderKind); - embedder.customizeForResolve(getWorkspaceMap(), console, process); + embedder.customizeForResolve(getWorkspaceMap(), console, process, false); embedder.clearCachesFor(mavenProject.getMavenId()); try { task.run(embedder); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/RemoveManagedFilesAction.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/RemoveManagedFilesAction.java index 12cdead53efb..33889ee9d368 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/RemoveManagedFilesAction.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/RemoveManagedFilesAction.java @@ -20,34 +20,20 @@ import com.intellij.notification.NotificationType; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.MavenUtil; import org.jetbrains.idea.maven.utils.actions.MavenAction; import org.jetbrains.idea.maven.utils.actions.MavenActionUtil; +import java.util.ArrayList; import java.util.List; public class RemoveManagedFilesAction extends MavenAction { @Override protected boolean isAvailable(AnActionEvent e) { if (!super.isAvailable(e)) return false; - - List<VirtualFile> files = MavenActionUtil.getMavenProjectsFiles(e.getDataContext()); - if (files.isEmpty()) return false; - - return files.size() == 1 || isAllFilesAreManaged(MavenActionUtil.getProjectsManager(e.getDataContext()), files); - } - - private static boolean isAllFilesAreManaged(@NotNull MavenProjectsManager projectsManager, List<VirtualFile> files) { - for (VirtualFile file : files) { - if (!projectsManager.isManagedFile(file)) { - return false; - } - } - - return true; + return MavenActionUtil.getMavenProjectsFiles(e.getDataContext()).size() > 0; } @Override @@ -57,34 +43,47 @@ public class RemoveManagedFilesAction extends MavenAction { MavenProjectsManager projectsManager = MavenActionUtil.getProjectsManager(context); List<VirtualFile> selectedFiles = MavenActionUtil.getMavenProjectsFiles(context); - if (selectedFiles.size() != 1) return; - - VirtualFile pomXml = selectedFiles.get(0); - - if (!projectsManager.isManagedFile(pomXml)) { - MavenProject mavenProject = projectsManager.findProject(pomXml); - assert mavenProject != null; + List<VirtualFile> removableFiles = new ArrayList<VirtualFile>(); - String aggregatorDescription = ""; - - MavenProject aggregator = projectsManager.findAggregator(mavenProject); - - if (aggregator != null) { - aggregatorDescription = " (" + aggregator.getMavenId().getDisplayString() + ')'; + for (VirtualFile pomXml : selectedFiles) { + if (projectsManager.isManagedFile(pomXml)) { + removableFiles.add(pomXml); } + else { + notifyUserIfNeeded(context, projectsManager, selectedFiles, pomXml); + } + } + projectsManager.removeManagedFiles(removableFiles); + } + + private static void notifyUserIfNeeded(DataContext context, + MavenProjectsManager projectsManager, + List<VirtualFile> selectedFiles, + VirtualFile pomXml) { + MavenProject mavenProject = projectsManager.findProject(pomXml); + assert mavenProject != null; - Notification notification = new Notification(MavenUtil.MAVEN_NOTIFICATION_GROUP, "Failed to remove project", - "You can not remove selected project because it's " + - "imported as a module of another project" + - aggregatorDescription - +". You can use Ignore action. Only root project can be removed.", - NotificationType.ERROR); + MavenProject aggregator = projectsManager.findAggregator(mavenProject); + while (aggregator != null && !projectsManager.isManagedFile(aggregator.getFile())) { + aggregator = projectsManager.findAggregator(aggregator); + } - notification.setImportant(true); - notification.notify(MavenActionUtil.getProject(context)); - return; + if (aggregator != null && !selectedFiles.contains(aggregator.getFile())) { + notifyUser(context, mavenProject, aggregator); } + } - projectsManager.removeManagedFiles(selectedFiles); + private static void notifyUser(DataContext context, MavenProject mavenProject, MavenProject aggregator) { + String aggregatorDescription = " (" + aggregator.getMavenId().getDisplayString() + ')'; + Notification notification = new Notification(MavenUtil.MAVEN_NOTIFICATION_GROUP, "Failed to remove project", + "You can not remove " + mavenProject.getName() + " because it's " + + "imported as a module of another project" + + aggregatorDescription + + ". You can use Ignore action. Only root project can be removed.", + NotificationType.ERROR + ); + + notification.setImportant(true); + notification.notify(MavenActionUtil.getProject(context)); } -} +}
\ No newline at end of file diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java index c5ac93cd6d7b..a0882e7c87fd 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java @@ -49,7 +49,7 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper<MavenServ } public void customizeForResolve(MavenConsole console, MavenProgressIndicator indicator) { - setCustomization(console, indicator, null, false); + setCustomization(console, indicator, null, false, false); perform(new Retriable<Object>() { @Override public Object execute() throws RemoteException { @@ -59,8 +59,8 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper<MavenServ }); } - public void customizeForResolve(MavenWorkspaceMap workspaceMap, MavenConsole console, MavenProgressIndicator indicator) { - setCustomization(console, indicator, workspaceMap, false); + public void customizeForResolve(MavenWorkspaceMap workspaceMap, MavenConsole console, MavenProgressIndicator indicator, boolean alwaysUpdateSnapshot) { + setCustomization(console, indicator, workspaceMap, false, alwaysUpdateSnapshot); perform(new Retriable<Object>() { @Override public Object execute() throws RemoteException { @@ -73,7 +73,7 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper<MavenServ public void customizeForStrictResolve(MavenWorkspaceMap workspaceMap, MavenConsole console, MavenProgressIndicator indicator) { - setCustomization(console, indicator, workspaceMap, true); + setCustomization(console, indicator, workspaceMap, true, false); perform(new Retriable<Object>() { @Override public Object execute() throws RemoteException { @@ -87,7 +87,8 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper<MavenServ getOrCreateWrappee().customize(myCustomization.workspaceMap, myCustomization.failOnUnresolvedDependency, myCustomization.console, - myCustomization.indicator); + myCustomization.indicator, + myCustomization.alwaysUpdateSnapshot); } @NotNull @@ -243,12 +244,14 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper<MavenServ private synchronized void setCustomization(MavenConsole console, MavenProgressIndicator indicator, MavenWorkspaceMap workspaceMap, - boolean failOnUnresolvedDependency) { + boolean failOnUnresolvedDependency, + boolean alwaysUpdateSnapshot) { resetCustomization(); myCustomization = new Customization(MavenServerManager.wrapAndExport(console), MavenServerManager.wrapAndExport(indicator), workspaceMap, - failOnUnresolvedDependency); + failOnUnresolvedDependency, + alwaysUpdateSnapshot); } private synchronized void resetCustomization() { @@ -276,15 +279,18 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper<MavenServ private final MavenWorkspaceMap workspaceMap; private final boolean failOnUnresolvedDependency; + private final boolean alwaysUpdateSnapshot; private Customization(MavenServerConsole console, MavenServerProgressIndicator indicator, MavenWorkspaceMap workspaceMap, - boolean failOnUnresolvedDependency) { + boolean failOnUnresolvedDependency, + boolean alwaysUpdateSnapshot) { this.console = console; this.indicator = indicator; this.workspaceMap = workspaceMap; this.failOnUnresolvedDependency = failOnUnresolvedDependency; + this.alwaysUpdateSnapshot = alwaysUpdateSnapshot; } } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenMergingUpdateQueue.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenMergingUpdateQueue.java index cb9ec71caa7f..e988b98add51 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenMergingUpdateQueue.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenMergingUpdateQueue.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,7 +78,7 @@ public class MavenMergingUpdateQueue extends MergingUpdateQueue { try { EditorEventMulticaster multicaster = EditorFactory.getInstance().getEventMulticaster(); - multicaster.addCaretListener(new CaretListener() { + multicaster.addCaretListener(new CaretAdapter() { public void caretPositionChanged(CaretEvent e) { MavenMergingUpdateQueue.this.restartTimer(); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/vfs/MavenPropertiesVirtualFile.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/vfs/MavenPropertiesVirtualFile.java index 7a8ccb550b00..000b855c5ac4 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/vfs/MavenPropertiesVirtualFile.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/vfs/MavenPropertiesVirtualFile.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. @@ -52,46 +52,57 @@ public class MavenPropertiesVirtualFile extends VirtualFile { return builder.toString().getBytes(); } + @Override @NotNull public String getName() { return myPath; } + @Override @NotNull public VirtualFileSystem getFileSystem() { return myFS; } + @Override + @NotNull public String getPath() { return myPath; } + @Override public boolean isWritable() { return false; } + @Override public boolean isDirectory() { return false; } + @Override public boolean isValid() { return true; } + @Override public VirtualFile getParent() { return null; } + @Override public VirtualFile[] getChildren() { return null; } + @Override @NotNull public byte[] contentsToByteArray() throws IOException { if (myContent == null) throw new IOException(); return myContent; } + @Override public long getTimeStamp() { return -1; } @@ -101,17 +112,21 @@ public class MavenPropertiesVirtualFile extends VirtualFile { return myContent.hashCode(); } + @Override public long getLength() { return myContent.length; } + @Override public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) { } + @Override public InputStream getInputStream() throws IOException { return VfsUtilCore.byteStreamSkippingBOM(myContent,this); } + @Override @NotNull public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) throws IOException { throw new UnsupportedOperationException(); diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 337fe0c5840f..5ef7e212f02b 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -2,7 +2,21 @@ <id>org.jetbrains.idea.maven</id> <name>Maven Integration</name> - <description>Import Maven projects and execute Maven goals</description> + <description> + <![CDATA[ + This plugin provides <a href="http://maven.apache.org/">Maven</a> support. + The following features are available: + <ul> + <li>Maven Projects tool window.</li> + <li>Dedicated module type.</li> + <li>Maven repositories support.</li> + <li>Full editing support for pom.xml file.</li> + <li>Possibility to import Maven projects.</li> + <li>Running and debugging Maven goals.</li> + <li>Compiling.</li> + </ul> + ]]> + </description> <vendor>JetBrains</vendor> <extensionPoints> diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesFileType.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesFileType.java index 6d9d3eef17a4..fb0f8d4fdaf3 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesFileType.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesFileType.java @@ -63,12 +63,10 @@ public class PropertiesFileType extends LanguageFileType { @Override public String getCharset(@NotNull VirtualFile file, final byte[] content) { - final EncodingRegistry encodingManager = EncodingRegistry.getInstance(); - if (encodingManager != null) { - final Charset encoding = encodingManager.getEncoding(file, true); - if (encoding != null) return encoding.toString(); + Charset charset = EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file); + if (charset == null) { + charset = CharsetToolkit.getDefaultSystemCharset(); } - final Charset charset = CharsetToolkit.getDefaultSystemCharset(); - return charset != null ? charset.toString() : null; + return charset != null ? charset.name() : null; } } diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java index 7a48ff9000ba..f61c3b87e80b 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.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. @@ -42,15 +42,19 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { return myResourceBundle; } + @Override @NotNull public VirtualFileSystem getFileSystem() { return LocalFileSystem.getInstance(); } + @Override + @NotNull public String getPath() { return getName(); } + @Override @NotNull public String getName() { return myResourceBundle.getBaseName(); @@ -71,71 +75,88 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { return myResourceBundle.hashCode(); } + @Override public void rename(Object requestor, @NotNull String newName) throws IOException { } + @Override public boolean isWritable() { return true; } + @Override public boolean isDirectory() { return false; } + @Override public boolean isValid() { return true; } + @Override public VirtualFile getParent() { return myResourceBundle.getBaseDirectory(); } + @Override public VirtualFile[] getChildren() { return EMPTY_ARRAY; } + @Override public VirtualFile createChildDirectory(Object requestor, String name) throws IOException { throw new UnsupportedOperationException(); } + @Override public VirtualFile createChildData(Object requestor, @NotNull String name) throws IOException { throw new UnsupportedOperationException(); } + @Override public void delete(Object requestor) throws IOException { //todo } + @Override public void move(Object requestor, @NotNull VirtualFile newParent) throws IOException { //todo } + @Override public InputStream getInputStream() throws IOException { throw new UnsupportedOperationException(); } + @Override @NotNull public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) throws IOException { throw new UnsupportedOperationException(); } + @Override @NotNull public byte[] contentsToByteArray() throws IOException { throw new UnsupportedOperationException(); } + @Override public long getModificationStamp() { return 0; } + @Override public long getTimeStamp() { return 0; } + @Override public long getLength() { return 0; } + @Override public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) { } diff --git a/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java b/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java index 370f07fab505..de96b39705e7 100644 --- a/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java +++ b/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java @@ -1,3 +1,18 @@ +/* + * 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. + * 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.lang.properties.xml; import com.intellij.ide.highlighter.XmlFileType; @@ -52,16 +67,19 @@ public class XmlPropertiesIndex extends FileBasedIndexExtension<XmlPropertiesInd return this; } + @NotNull @Override public KeyDescriptor<Key> getKeyDescriptor() { return this; } + @NotNull @Override public DataExternalizer<String> getValueExternalizer() { return ENUMERATOR_STRING_DESCRIPTOR; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return this; @@ -78,7 +96,7 @@ public class XmlPropertiesIndex extends FileBasedIndexExtension<XmlPropertiesInd } @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return true; } @@ -139,7 +157,7 @@ public class XmlPropertiesIndex extends FileBasedIndexExtension<XmlPropertiesInd private final byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); @Override - public void save(DataOutput out, Key value) throws IOException { + public void save(@NotNull DataOutput out, Key value) throws IOException { out.writeBoolean(value.isMarker); if (value.key != null) { IOUtil.writeUTFFast(buffer, out, value.key); @@ -147,7 +165,7 @@ public class XmlPropertiesIndex extends FileBasedIndexExtension<XmlPropertiesInd } @Override - public Key read(DataInput in) throws IOException { + public Key read(@NotNull DataInput in) throws IOException { boolean isMarker = in.readBoolean(); return isMarker ? MARKER_KEY : new Key(IOUtil.readUTFFast(buffer, in)); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.java index 8f6de1e7c749..8fe1fa52a938 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.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. @@ -21,6 +21,7 @@ import com.intellij.openapi.vcs.persistent.SmallMapSerializer; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorStringDescriptor; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.branchConfig.InfoStorage; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; @@ -99,7 +100,7 @@ public class SvnLoadedBrachesStorage { private DataExternalizer<Map<String, Collection<SvnBranchItem>>> createExternalizer() { return new DataExternalizer<Map<String, Collection<SvnBranchItem>>>() { @Override - public void save(DataOutput out, Map<String, Collection<SvnBranchItem>> value) throws IOException { + public void save(@NotNull DataOutput out, Map<String, Collection<SvnBranchItem>> value) throws IOException { out.writeInt(value.size()); ArrayList<String> keys = new ArrayList<String>(value.keySet()); Collections.sort(keys); @@ -117,7 +118,7 @@ public class SvnLoadedBrachesStorage { } @Override - public Map<String, Collection<SvnBranchItem>> read(DataInput in) throws IOException { + public Map<String, Collection<SvnBranchItem>> read(@NotNull DataInput in) throws IOException { final HashMap<String, Collection<SvnBranchItem>> map = new HashMap<String, Collection<SvnBranchItem>>(); int mapSize = in.readInt(); for (int i = 0; i < mapSize; i++) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnBranchPointsCalculator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnBranchPointsCalculator.java index 2fd8b8b6dfa8..5d7bd6d3aa61 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnBranchPointsCalculator.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnBranchPointsCalculator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -28,6 +28,7 @@ import com.intellij.util.containers.MultiMap; import com.intellij.util.continuation.TaskDescriptor; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorStringDescriptor; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.history.CopyData; @@ -88,7 +89,7 @@ public class SvnBranchPointsCalculator { } private static class BranchDataExternalizer implements DataExternalizer<TreeMap<String,BranchCopyData>> { - public void save(DataOutput out, TreeMap<String,BranchCopyData> value) throws IOException { + public void save(@NotNull DataOutput out, TreeMap<String,BranchCopyData> value) throws IOException { out.writeInt(value.size()); for (Map.Entry<String, BranchCopyData> entry : value.entrySet()) { out.writeUTF(entry.getKey()); @@ -100,7 +101,7 @@ public class SvnBranchPointsCalculator { } } - public TreeMap<String,BranchCopyData> read(DataInput in) throws IOException { + public TreeMap<String,BranchCopyData> read(@NotNull DataInput in) throws IOException { final TreeMap<String,BranchCopyData> result = new TreeMap<String, BranchCopyData>(); final int num = in.readInt(); diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/context/ContextTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/context/ContextTest.java index 029b9a7d208e..db609abb2b85 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/context/ContextTest.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/context/ContextTest.java @@ -21,13 +21,15 @@ import com.intellij.openapi.project.impl.ProjectImpl; import com.intellij.openapi.util.io.FileUtil; import com.intellij.tasks.TaskManagerTestCase; import com.intellij.xdebugger.XDebuggerManager; -import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XBreakpointManager; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.breakpoints.XBreakpointType; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl; import org.intellij.plugins.xsltDebugger.XsltBreakpointType; import java.io.File; +import java.util.Collection; import java.util.List; /** @@ -78,10 +80,12 @@ public class ContextTest extends TaskManagerTestCase { final WorkingContextManager manager = getContextManager(); final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(getProject()).getBreakpointManager(); + final XsltBreakpointType type = XBreakpointType.EXTENSION_POINT_NAME.findExtension(XsltBreakpointType.class); + ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { XLineBreakpointImpl<XBreakpointProperties> breakpoint = - (XLineBreakpointImpl<XBreakpointProperties>)breakpointManager.addLineBreakpoint(new XsltBreakpointType(), "foo", 0, null); + (XLineBreakpointImpl<XBreakpointProperties>)breakpointManager.addLineBreakpoint(type, "foo", 0, null); final String name = "foo"; manager.saveContext(name, null); @@ -89,8 +93,8 @@ public class ContextTest extends TaskManagerTestCase { } }); manager.loadContext("foo"); - XBreakpoint<?>[] breakpoints = breakpointManager.getAllBreakpoints(); - assertEquals(1, breakpoints.length); + Collection<? extends XLineBreakpoint<XBreakpointProperties>> breakpoints = breakpointManager.getBreakpoints(type); + assertEquals(1, breakpoints.size()); manager.clearContext(); } diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalPanel.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalPanel.java index 0c344441e967..e9de7fb33f68 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalPanel.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalPanel.java @@ -89,15 +89,16 @@ public class JBTerminalPanel extends TerminalPanel implements FocusListener, Ter @Override public void actionPerformed(AnActionEvent e) { if (e.getInputEvent() instanceof KeyEvent) { - action.update(e); - if (e.getPresentation().isEnabled()) { - action.actionPerformed(e); + AnActionEvent event = new AnActionEvent(e.getInputEvent(), e.getDataContext(), e.getPlace(), new Presentation(), e.getActionManager(), e.getModifiers()); + action.update(event); + if (event.getPresentation().isEnabled()) { + action.actionPerformed(event); } else { - terminalPanel.handleKeyEvent((KeyEvent)e.getInputEvent()); + terminalPanel.handleKeyEvent((KeyEvent)event.getInputEvent()); } - e.getInputEvent().consume(); + event.getInputEvent().consume(); } } }; diff --git a/plugins/ui-designer-core/src/META-INF/plugin.xml b/plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml index 18d7453c0226..ede0d2b92f01 100644 --- a/plugins/ui-designer-core/src/META-INF/plugin.xml +++ b/plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml @@ -1,12 +1,6 @@ <idea-plugin version="2"> - <name>UI Designer (Core)</name> - <id>com.intellij.ui-designer-new</id> - <description> - Provides shared functionality for visual editing plugins. - </description> - <vendor>JetBrains</vendor> - <resource-bundle>messages.DesignerBundle</resource-bundle> + <module value="com.intellij.ui-designer-new"/> <depends>com.intellij.modules.lang</depends> @@ -19,10 +13,6 @@ </component> </project-components> - <extensions defaultExtensionNs="com.intellij"> - <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/> - </extensions> - <extensionPoints> <extensionPoint qualifiedName="Designer.customizations" interface="com.intellij.designer.DesignerCustomizations"/> </extensionPoints> diff --git a/plugins/ui-designer-core/src/com/intellij/designer/DesignerEditor.java b/plugins/ui-designer-core/src/com/intellij/designer/DesignerEditor.java index 7f29d4e3d865..4aee4999f707 100644 --- a/plugins/ui-designer-core/src/com/intellij/designer/DesignerEditor.java +++ b/plugins/ui-designer-core/src/com/intellij/designer/DesignerEditor.java @@ -73,6 +73,12 @@ public abstract class DesignerEditor extends UserDataHolderBase implements FileE return myDesignerPanel.getPreferredFocusedComponent(); } + @NotNull + @Override + public String getName() { + return "Design"; + } + @Override public void dispose() { myDesignerPanel.dispose(); diff --git a/plugins/ui-designer-core/src/com/intellij/designer/designSurface/tools/DragTracker.java b/plugins/ui-designer-core/src/com/intellij/designer/designSurface/tools/DragTracker.java index b506ff73f957..b2eb832319f5 100644 --- a/plugins/ui-designer-core/src/com/intellij/designer/designSurface/tools/DragTracker.java +++ b/plugins/ui-designer-core/src/com/intellij/designer/designSurface/tools/DragTracker.java @@ -125,23 +125,26 @@ public class DragTracker extends SelectionTracker { myContext.setLocation(getLocation()); if (myContext.getComponents() == null) { - List<RadComponent> components = RadComponent.getPureSelection(myArea.getSelection()); + List<RadComponent> components = calculateContextComponents(RadComponent.getPureSelection(myArea.getSelection())); + myContext.setComponents(components); - RadComponent parent = null; for (RadComponent component : components) { - if (parent == null) { - parent = component.getParent(); - } - else if (parent != component.getParent()) { - components = Collections.emptyList(); - break; - } + component.processDropOperation(myContext); } + } + } - myContext.setComponents(components); - for (RadComponent component : components) { - component.processDropOperation(myContext); + protected List<RadComponent> calculateContextComponents(List<RadComponent> components) { + RadComponent parent = null; + for (RadComponent component : components) { + if (parent == null) { + parent = component.getParent(); + } + else if (parent != component.getParent()) { + components = Collections.emptyList(); + break; } } + return components; } }
\ No newline at end of file diff --git a/plugins/ui-designer-core/src/com/intellij/designer/model/MetaManager.java b/plugins/ui-designer-core/src/com/intellij/designer/model/MetaManager.java index 0727b485d2fe..cfa76ef78ffd 100644 --- a/plugins/ui-designer-core/src/com/intellij/designer/model/MetaManager.java +++ b/plugins/ui-designer-core/src/com/intellij/designer/model/MetaManager.java @@ -60,19 +60,18 @@ public abstract class MetaManager extends ModelLoader { Map<MetaModel, List<String>> modelToMorphing = new HashMap<MetaModel, List<String>>(); - for (Object element : rootElement.getChildren(META)) { - loadModel(classLoader, (Element)element, modelToMorphing); + for (Element element : rootElement.getChildren(META)) { + loadModel(classLoader, element, modelToMorphing); } - for (Object element : rootElement.getChild(PALETTE).getChildren(GROUP)) { - loadGroup((Element)element); + for (Element element : rootElement.getChild(PALETTE).getChildren(GROUP)) { + loadGroup(element); } Element wrapInElement = rootElement.getChild(WRAP_IN); if (wrapInElement != null) { - for (Object element : wrapInElement.getChildren(ITEM)) { - Element item = (Element)element; - myWrapModels.add(myTag2Model.get(item.getAttributeValue("tag"))); + for (Element element : wrapInElement.getChildren(ITEM)) { + myWrapModels.add(myTag2Model.get(element.getAttributeValue("tag"))); } } @@ -210,8 +209,7 @@ public abstract class MetaManager extends ModelLoader { protected PaletteGroup loadGroup(Element element) throws Exception { PaletteGroup group = createPaletteGroup(element.getAttributeValue(NAME)); - for (Object child : element.getChildren(ITEM)) { - Element itemElement = (Element)child; + for (Element itemElement : element.getChildren(ITEM)) { MetaModel model = getModelByTag(itemElement.getAttributeValue(TAG)); PaletteItem paletteItem = model.getPaletteItem(); @@ -230,8 +228,8 @@ public abstract class MetaManager extends ModelLoader { } group.addItem(paletteItem); - for (Object grandChild : itemElement.getChildren(ITEM)) { - group.addItem(createVariationPaletteItem(paletteItem, model, (Element)grandChild)); + for (Element grandChild : itemElement.getChildren(ITEM)) { + group.addItem(createVariationPaletteItem(paletteItem, model, grandChild)); } } else { diff --git a/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java b/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java index f2d2b9a05a02..defecc586594 100644 --- a/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java +++ b/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java @@ -35,7 +35,6 @@ import org.jetbrains.jps.builders.java.JavaBuilderUtil; import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; import org.jetbrains.jps.builders.logging.ProjectBuilderLogger; import org.jetbrains.jps.incremental.*; -import org.jetbrains.jps.incremental.instrumentation.BaseInstrumentingBuilder; import org.jetbrains.jps.incremental.instrumentation.ClassProcessingBuilder; import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.messages.CompilerMessage; @@ -123,7 +122,7 @@ public class FormsInstrumenter extends FormsBuilder { } } finally { - context.processMessage(new ProgressMessage("Finished instrumenting forms [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage("Finished instrumenting forms [" + chunk.getPresentableShortName() + "]")); } return ExitCode.OK; @@ -197,14 +196,14 @@ public class FormsInstrumenter extends FormsBuilder { addBinding(compiled.getSourceFile(), formFile, instrumented); try { - context.processMessage(new ProgressMessage("Instrumenting forms... [" + chunk.getName() + "]")); + context.processMessage(new ProgressMessage("Instrumenting forms... [" + chunk.getPresentableShortName() + "]")); final BinaryContent originalContent = compiled.getContent(); final ClassReader classReader = new ClassReader(originalContent.getBuffer(), originalContent.getOffset(), originalContent.getLength()); - final int version = BaseInstrumentingBuilder.getClassFileVersion(classReader); - final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(BaseInstrumentingBuilder.getAsmClassWriterFlags(version), finder); + final int version = ClassProcessingBuilder.getClassFileVersion(classReader); + final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(ClassProcessingBuilder.getAsmClassWriterFlags(version), finder); final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, finder, nestedFormsLoader, false, classWriter); final byte[] patchedBytes = codeGenerator.patchClass(classReader); if (patchedBytes != null) { diff --git a/plugins/ui-designer/jps-plugin/ui-designer-jps-plugin.iml b/plugins/ui-designer/jps-plugin/ui-designer-jps-plugin.iml index f46639653871..70277d7b2991 100644 --- a/plugins/ui-designer/jps-plugin/ui-designer-jps-plugin.iml +++ b/plugins/ui-designer/jps-plugin/ui-designer-jps-plugin.iml @@ -16,6 +16,7 @@ <orderEntry type="module" module-name="instrumentation-util" /> <orderEntry type="module" module-name="forms-compiler" /> <orderEntry type="module" module-name="forms_rt" /> + <orderEntry type="module" module-name="jps-serialization-tests" scope="TEST" /> </component> </module> diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java index 18f23044ac0f..c9702518612f 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.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. @@ -55,11 +55,13 @@ public class FormClassIndex extends ScalarIndexExtension<String> { return myDataIndexer; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.GUI_DESIGNER_FORM); diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java index 82e218ff65c1..f34f0fd67cb4 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java @@ -132,21 +132,24 @@ public class XsltSymbolIndex extends FileBasedIndexExtension<String, XsltSymbolI }; } + @NotNull @Override public DataExternalizer<Kind> getValueExternalizer() { return new EnumDataDescriptor<Kind>(Kind.class); } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return new EnumeratorStringDescriptor(); } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML) { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return !(file.getFileSystem() instanceof JarFileSystem); } }; diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java index dfdded1e6a95..b8fc055afc9b 100644 --- a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java +++ b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java @@ -47,7 +47,7 @@ public class XsltStackFrame extends XStackFrame { } @Override - public void customizePresentation(ColoredTextContainer component) { + public void customizePresentation(@NotNull ColoredTextContainer component) { if (myDebuggerSession.getCurrentState() == Debugger.State.SUSPENDED) { try { _customizePresentation(component); diff --git a/python/helpers/pycharm_generator_utils/constants.py b/python/helpers/pycharm_generator_utils/constants.py index 4ea8cf17309a..01079c47f687 100644 --- a/python/helpers/pycharm_generator_utils/constants.py +++ b/python/helpers/pycharm_generator_utils/constants.py @@ -6,7 +6,7 @@ import string import time -VERSION = "1.133" +VERSION = "1.135" OUT_ENCODING = 'utf-8' diff --git a/python/helpers/pycharm_generator_utils/module_redeclarator.py b/python/helpers/pycharm_generator_utils/module_redeclarator.py index 83778790a1c5..dcae2b5471c6 100644 --- a/python/helpers/pycharm_generator_utils/module_redeclarator.py +++ b/python/helpers/pycharm_generator_utils/module_redeclarator.py @@ -77,6 +77,7 @@ class ModuleRedeclarator(object): self.footer_buf = Buf(self) self.indent_size = indent_size self._indent_step = " " * self.indent_size + self.split_modules = False # self.imported_modules = {"": the_builtins} # explicit module imports: {"name": module} self.hidden_imports = {} # {'real_mod_name': 'alias'}; we alias names with "__" since we don't want them exported @@ -115,7 +116,7 @@ class ModuleRedeclarator(object): def flush(self): init = None try: - if self.mod_filename and len(self.classes_buffs) >= 30: + if self.split_modules: mod_path = self.outfile.strip(".py") fname = build_output_name(mod_path, "__init__") @@ -128,11 +129,9 @@ class ModuleRedeclarator(object): fname = build_output_name(mod_path, buf.name) dummy = fopen(fname, "w") self.header_buf.flush(dummy) + self.imports_buf.flush(dummy) buf.flush(dummy) - data += "from " - if version[0] >= 3: - data += "." - data += buf.name + " import " + buf.name + "\n" + data += self.create_local_import(buf.name) dummy.close() init.write(data) @@ -158,6 +157,13 @@ class ModuleRedeclarator(object): fake_builtin_init.__doc__ = object.__init__.__doc__ # this forces class's doc to be used instead + def create_local_import(self, name): + if len(name.split(".")) > 1: return "" + data = "from " + if version[0] >= 3: + data += "." + data += name + " import " + name + "\n" + return data def find_imported_name(self, item): """ @@ -636,6 +642,11 @@ class ModuleRedeclarator(object): else: bases_list.append(base_name) base_def = "(" + ", ".join(bases_list) + ")" + + for base in bases_list: + local_import = self.create_local_import(base) + if local_import: + out(indent, local_import) out(indent, "class ", p_name, base_def, ":", skipped_bases and " # skipped bases: " + ", ".join(skipped_bases) or "") out_doc_attr(out, p_class, indent + 1) @@ -968,6 +979,7 @@ class ModuleRedeclarator(object): ins_index = i # we could not go farther than current ins_index break # ...and need not go fartehr than first known child cls_list.insert(ins_index, (cls_name, get_mro(cls))) + self.split_modules = self.mod_filename and len(cls_list) >= 30 for item_name in [cls_item[0] for cls_item in cls_list]: buf = ClassBuf(item_name, self) self.classes_buffs.append(buf) diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index f7bfb322c7d5..590687dcd0f9 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -764,7 +764,7 @@ class PyDB: del self.exception_set[exception] self.always_exception_set.remove(exception) except: - pass + pydev_log.debug("Error while removing exception"%sys.exc_info()[0]); update_exception_hook(self) elif cmd_id == CMD_LOAD_SOURCE: diff --git a/python/helpers/pydev/pydevd_breakpoints.py b/python/helpers/pydev/pydevd_breakpoints.py index 0a6644b8cf01..beebebf4abed 100644 --- a/python/helpers/pydev/pydevd_breakpoints.py +++ b/python/helpers/pydev/pydevd_breakpoints.py @@ -127,6 +127,9 @@ def excepthook(exctype, value, tb): debugger.force_post_mortem_stop += 1 pydevd_tracing.SetTrace(None) #no tracing from here + + pydev_log.debug('Handling post-mortem stop on exception breakpoint %s'% exception_breakpoint.qname) + debugger.handle_post_mortem_stop(thread.additionalInfo, thread) #======================================================================================================================= diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index 592a96900c73..376065fbae03 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -311,10 +311,12 @@ class ReaderThread(PyDBDaemonThread): break while buffer.find('\n') != -1: command, buffer = buffer.split('\n', 1) - pydev_log.debug('Received command: >>%s<<\n' % (command,)) + args = command.split('\t', 2) try: - self.processCommand(int(args[0]), int(args[1]), args[2]) + cmd_id = int(args[0]) + pydev_log.debug('Received command: %s %s\n' % (ID_TO_MEANING.get(str(cmd_id), '???'), command,)) + self.processCommand(cmd_id, int(args[1]), args[2]) except: traceback.print_exc() sys.stderr.write("Can't process net command: %s\n" % command) @@ -383,7 +385,7 @@ class WriterThread(PyDBDaemonThread): out = cmd.getOutgoing() if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1: - out_message = 'sending cmd: ' + out_message = 'Sending cmd: ' out_message += ID_TO_MEANING.get(out[:3], 'UNKNOWN') out_message += ' ' out_message += out diff --git a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java index b0790146e6f6..ed2163afd9bd 100644 --- a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java +++ b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java @@ -25,9 +25,9 @@ import com.intellij.ui.CollectionComboBoxModel; import com.intellij.ui.ComboboxWithBrowseButton; import com.intellij.util.NullableConsumer; import com.intellij.util.containers.ContainerUtil; -import com.jetbrains.python.configuration.PythonSdkDetailsDialog; +import com.jetbrains.python.configuration.PyConfigurableInterpreterList; import com.jetbrains.python.sdk.PyDetectedSdk; -import com.jetbrains.python.sdk.PythonSdkType; +import com.jetbrains.python.sdk.PythonSdkDetailsStep; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import org.jetbrains.annotations.Nullable; @@ -63,14 +63,7 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { }); addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - final List<Sdk> sdks = PythonSdkType.getAllSdks(); - PythonSdkDetailsDialog dialog = new PythonSdkDetailsDialog(project, new NullableConsumer<Sdk>() { - @Override - public void consume(@Nullable Sdk sdk) { - comboBox.setModel(new CollectionComboBoxModel(sdks, sdk)); - } - }); - dialog.show(); + showOptions(project); notifyChanged(e); } }); @@ -81,6 +74,19 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { }); } + private void showOptions(final Project project) { + final PyConfigurableInterpreterList interpreterList = PyConfigurableInterpreterList.getInstance(project); + final Sdk[] sdks = interpreterList.getModel().getSdks(); + PythonSdkDetailsStep.show(project, sdks, null, this, getButton().getLocationOnScreen(), new NullableConsumer<Sdk>() { + @Override + public void consume(@Nullable Sdk sdk) { + //noinspection unchecked + getComboBox().setModel(new CollectionComboBoxModel(interpreterList.getAllPythonSdks(), sdk)); + } + } + ); + } + private void notifyChanged(ActionEvent e) { for (ActionListener changedListener : myChangedListeners) { changedListener.actionPerformed(e); diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index 242d0087e682..42dbef84b6ce 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -16,7 +16,6 @@ package com.jetbrains.python.configuration; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.ex.EditorEx; @@ -26,6 +25,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModel; import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; @@ -36,6 +36,9 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.FixedSizeButton; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.CollectionComboBoxModel; import com.intellij.util.NullableConsumer; @@ -61,7 +64,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private final Project myProject; @Nullable private final Module myModule; private MySdkModelListener mySdkModelListener; - private boolean myAddedSdk = false; + private List<Sdk> myAddedSdks = new ArrayList<Sdk>(); private PyConfigurableInterpreterList myInterpreterList; private ProjectSdksModel myProjectSdksModel; @@ -70,6 +73,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private JButton myDetailsButton; private static final String SHOW_ALL = "Show All"; private NullableConsumer<Sdk> myDetailsCallback; + private PythonSdkDetailsDialog myMoreDialog; public PyActiveSdkConfigurable(@NotNull Project project) { myModule = null; @@ -87,7 +91,6 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private void initContent() { myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); - myInterpreterList.setSdkCombo(mySdkCombo); myProjectSdksModel = myInterpreterList.getModel(); mySdkModelListener = new MySdkModelListener(this); @@ -98,8 +101,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public void actionPerformed(ActionEvent e) { final Sdk selectedSdk = (Sdk)mySdkCombo.getSelectedItem(); myPackagesPanel.updatePackages(selectedSdk != null ? new PyPackageManagementService(myProject, selectedSdk) : null); - if (selectedSdk != null) - myPackagesPanel.updateNotifications(selectedSdk); + myPackagesPanel.updateNotifications(selectedSdk); } }); myDetailsCallback = new NullableConsumer<Sdk>() { @@ -110,7 +112,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { final Sdk addedSdk = SdkConfigurationUtil.setupSdk(myProjectSdksModel.getSdks(), sdk.getHomeDirectory(), PythonSdkType.getInstance(), true, null, null); - myAddedSdk = true; + myAddedSdks.add(addedSdk); myProjectSdksModel.addSdk(addedSdk); myProjectSdksModel.removeSdk(sdk); mySdkCombo.setSelectedItem(addedSdk); @@ -127,26 +129,28 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { } } }; - + myMoreDialog = myModule == null ? new PythonSdkDetailsDialog(myProject, myDetailsCallback) : + new PythonSdkDetailsDialog(myModule, myDetailsCallback); myDetailsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - PythonSdkDetailsStep - .show(myProject, myProjectSdksModel.getSdks(), - myModule == null ? new PythonSdkDetailsDialog(myProject, myDetailsCallback) : - new PythonSdkDetailsDialog(myModule, myDetailsCallback), myMainPanel, - myDetailsButton.getLocationOnScreen(), true, + PythonSdkDetailsStep.show(myProject, myProjectSdksModel.getSdks(), + myMoreDialog, myMainPanel, + myDetailsButton.getLocationOnScreen(), new NullableConsumer<Sdk>() { @Override public void consume(Sdk sdk) { if (sdk == null) return; + final PyRemovedSdkService sdkService = PyRemovedSdkService.getInstance(); + sdkService.restoreSdk(sdk); if (myProjectSdksModel.findSdk(sdk) == null) { myProjectSdksModel.addSdk(sdk); - myAddedSdk = true; + myAddedSdks.add(sdk); } updateSdkList(false); mySdkCombo.getModel().setSelectedItem(sdk); myPackagesPanel.updatePackages(new PyPackageManagementService(myProject, sdk)); + myPackagesPanel.updateNotifications(sdk); } } ); @@ -184,8 +188,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { final PackagesNotificationPanel notificationsArea = new PackagesNotificationPanel(myProject); final JComponent notificationsComponent = notificationsArea.getComponent(); final Dimension preferredSize = mySdkCombo.getPreferredSize(); - notificationsComponent.setPreferredSize(new Dimension(500, preferredSize.height)); - + notificationsArea.hide(); myDetailsButton = new FixedSizeButton(); myDetailsButton.setIcon(PythonIcons.Python.InterpreterGear); //noinspection SuspiciousNameCombination @@ -211,7 +214,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.weightx = 0.0; myMainPanel.add(myDetailsButton, c); - c.insets = new Insets(2,2,2,2); + c.insets = new Insets(2,2,0,2); c.gridx = 0; c.gridy = 1; c.gridwidth = 3; @@ -219,7 +222,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.gridx = 0; c.gridy = 2; - c.weighty = 0.5; + c.weighty = 1.; c.gridwidth = 3; c.gridheight = GridBagConstraints.RELATIVE; c.fill = GridBagConstraints.BOTH; @@ -229,7 +232,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.gridx = 0; c.gridy = 3; c.gridwidth = 3; - + c.weighty = 0.; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.SOUTH; @@ -245,7 +248,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public boolean isModified() { final Sdk sdk = getSdk(); final Sdk selectedItem = (Sdk)mySdkCombo.getSelectedItem(); - return myAddedSdk || selectedItem instanceof PyDetectedSdk || sdk != myProjectSdksModel.findSdk(selectedItem); + return !myAddedSdks.isEmpty() || selectedItem instanceof PyDetectedSdk || sdk != myProjectSdksModel.findSdk(selectedItem); } @Nullable @@ -260,18 +263,20 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void apply() throws ConfigurationException { final Sdk item = (Sdk)mySdkCombo.getSelectedItem(); + Sdk newSdk = item; if (item instanceof PyDetectedSdk) { - ApplicationManager.getApplication().invokeLater(new Runnable() { + VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() { @Override - public void run() { - final Sdk sdk = SdkConfigurationUtil.createAndAddSDK(item.getName(), PythonSdkType.getInstance()); - myProjectSdksModel.removeSdk(item); - myProjectSdksModel.addSdk(sdk); - updateSdkList(true); - mySdkCombo.setSelectedItem(sdk); - setSdk(sdk); + public VirtualFile compute() { + return LocalFileSystem.getInstance().refreshAndFindFileByPath(item.getName()); } - }, ModalityState.any()); + }); + newSdk = SdkConfigurationUtil.setupSdk(ProjectJdkTable.getInstance().getAllJdks(), sdkHome, PythonSdkType.getInstance(), true, null, null); + if (newSdk != null) { + myProjectSdksModel.addSdk(newSdk); + mySdkCombo.setSelectedItem(newSdk); + myProjectSdksModel.apply(); + } } else { final Sdk sdk = myProjectSdksModel.findSdk(item); @@ -280,13 +285,13 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myProjectSdksModel.apply(null, true); mySdkCombo.setSelectedItem(item); } - else if (myAddedSdk) { - myProjectSdksModel.apply(null, true); + else if (!myAddedSdks.isEmpty()) { + myProjectSdksModel.apply(); } } final Sdk prevSdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); - final Sdk selectedSdk = setSdk(item); + final Sdk selectedSdk = setSdk(newSdk); // update string literals if different LanguageLevel was selected if (prevSdk != null && selectedSdk != null) { @@ -305,7 +310,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { } private Sdk setSdk(Sdk item) { - myAddedSdk = false; + myAddedSdks.clear(); final Sdk selectedSdk = myProjectSdksModel.findSdk(item); if (myModule == null) { final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject); @@ -342,8 +347,12 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void reset() { - myAddedSdk = false; - myProjectSdksModel.reset(myProject); + if (!myAddedSdks.isEmpty()) { + for (Sdk sdk : myAddedSdks) { + myProjectSdksModel.removeSdk(sdk); + } + } + myAddedSdks.clear(); resetSdkList(); } @@ -399,6 +408,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public void disposeUIResources() { myProjectSdksModel.removeListener(mySdkModelListener); myInterpreterList.disposeModel(); + Disposer.dispose(myMoreDialog.getDisposable()); } private static class MySdkModelListener implements SdkModel.Listener { @@ -410,7 +420,15 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void sdkAdded(Sdk sdk) { + final Object item = myConfigurable.mySdkCombo.getSelectedItem(); + myConfigurable.resetSdkList(); + + if (item instanceof PyDetectedSdk) { + final String path = ((PyDetectedSdk)item).getHomePath(); + if (path != null && path.equals(sdk.getHomePath())) + myConfigurable.mySdkCombo.setSelectedItem(sdk); + } } @Override diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java index 87b9163eb824..c7176dd811f9 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java @@ -15,6 +15,8 @@ */ package com.jetbrains.python.configuration; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; @@ -30,8 +32,10 @@ import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor; import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; /** * Manages the SDK model shared between PythonSdkConfigurable and PyActiveSdkConfigurable. @@ -40,16 +44,6 @@ import java.util.*; */ public class PyConfigurableInterpreterList { private ProjectSdksModel myModel; - private JComboBox mySdkCombo; - - public void setSdkCombo(final JComboBox sdkCombo) { - mySdkCombo = sdkCombo; - } - - public void setSelectedSdk(final Sdk selectedSdk) { - if (mySdkCombo != null) - mySdkCombo.setSelectedItem(selectedSdk); - } public static PyConfigurableInterpreterList getInstance(Project project) { return ServiceManager.getService(project, PyConfigurableInterpreterList.class); @@ -89,42 +83,51 @@ public class PyConfigurableInterpreterList { final boolean isVEnv2 = PythonSdkType.isVirtualEnv(o2); final boolean isRemote1 = PySdkUtil.isRemote(o1); final boolean isRemote2 = PySdkUtil.isRemote(o2); - final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(o1); - final PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(o2); - final LanguageLevel level1 = flavor1 != null ? flavor1.getLanguageLevel(o1) : LanguageLevel.getDefault(); - final LanguageLevel level2 = flavor2 != null ? flavor2.getLanguageLevel(o2) : LanguageLevel.getDefault(); if (isVEnv1) { - if (project != null && associatedWithCurrent(o1, project)) return -1; + if (project != null && associatedWithCurrent(o1, project)) { + if (associatedWithCurrent(o2, project)) return compareSdk(o1, o2); + return -1; + } if (isVEnv2) { - final int compare = Comparing.compare(level1, level2); - if (compare != 0) return -compare; - return Comparing.compare(o1.getName(), o2.getName()); + return compareSdk(o1, o2); } return -1; } - if (isVEnv2) { - return 1; - } + if (isVEnv2) return 1; if (isRemote1) return 1; if (isRemote2) return -1; + return compareSdk(o1, o2); + } + + private int compareSdk(final Sdk o1, final Sdk o2) { + final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(o1); + final PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(o2); + final LanguageLevel level1 = flavor1 != null ? flavor1.getLanguageLevel(o1) : LanguageLevel.getDefault(); + final LanguageLevel level2 = flavor2 != null ? flavor2.getLanguageLevel(o2) : LanguageLevel.getDefault(); final int compare = Comparing.compare(level1, level2); if (compare != 0) return -compare; return Comparing.compare(o1.getName(), o2.getName()); } }); - final Collection<String> sdkHomes = new ArrayList<String>(); + final List<String> sdkHomes = new ArrayList<String>(); sdkHomes.addAll(VirtualEnvSdkFlavor.INSTANCE.suggestHomePaths()); for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) { if (flavor instanceof VirtualEnvSdkFlavor) continue; sdkHomes.addAll(flavor.suggestHomePaths()); } - + Collections.sort(sdkHomes); for (String sdkHome : SdkConfigurationUtil.filterExistingPaths(PythonSdkType.getInstance(), sdkHomes, getModel().getSdks())) { result.add(new PyDetectedSdk(sdkHome)); } + Iterables.removeIf(result, new Predicate<Sdk>() { + @Override + public boolean apply(@Nullable Sdk input) { + return input != null && PyRemovedSdkService.getInstance().isRemoved(input); + } + }); return result; } diff --git a/python/ide/src/com/jetbrains/python/configuration/PyRemovedSdkService.java b/python/ide/src/com/jetbrains/python/configuration/PyRemovedSdkService.java new file mode 100644 index 000000000000..f0927f7d1c81 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyRemovedSdkService.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2013 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.jetbrains.python.configuration; + +import com.intellij.openapi.components.*; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.util.xmlb.XmlSerializerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +@State( + name = "PyRemovedSdkService", + storages = { + @Storage( + file = StoragePathMacros.APP_CONFIG + "/removedInterpreters.xml" + )} +) +public class PyRemovedSdkService implements PersistentStateComponent<PyRemovedSdkService> { + + public static PyRemovedSdkService getInstance() { + return ServiceManager.getService(PyRemovedSdkService.class); + } + + public Set<String> REMOVED_SDKS = new HashSet<String>(); + + public void removeSdk(@NotNull final Sdk sdk) { + REMOVED_SDKS.add(sdk.getHomePath()); + } + + public void restoreSdk(@NotNull final Sdk sdk) { + final String homePath = sdk.getHomePath(); + if (REMOVED_SDKS.contains(homePath)) { + REMOVED_SDKS.remove(homePath); + } + } + + public boolean isRemoved(@NotNull final Sdk sdk) { + final String homePath = sdk.getHomePath(); + return REMOVED_SDKS.contains(homePath); + } + + @Override + public PyRemovedSdkService getState() { + return this; + } + + @Override + public void loadState(PyRemovedSdkService state) { + XmlSerializerUtil.copyBean(state, this); + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonContentEntriesConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonContentEntriesConfigurable.java index f67260b6b07d..e573aacf142a 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonContentEntriesConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonContentEntriesConfigurable.java @@ -22,9 +22,12 @@ import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.NonDefaultProjectConfigurable; import com.intellij.openapi.options.OptionalConfigurable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.PlatformContentEntriesConfigurable; import com.intellij.util.ArrayUtil; +import com.intellij.util.PlatformUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.java.JavaSourceRootType; /** * @author yole @@ -50,6 +53,8 @@ public class PythonContentEntriesConfigurable extends ModuleAwareProjectConfigur @NotNull @Override protected Configurable createModuleConfigurable(Module module) { + if (PlatformUtils.isPyCharmCommunity()) + return new PlatformContentEntriesConfigurable(module, JavaSourceRootType.SOURCE); return new PyContentEntriesModuleConfigurable(module); } } diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java index 162ee67e08aa..68146c065a4e 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java @@ -18,11 +18,13 @@ package com.jetbrains.python.configuration; import com.google.common.collect.Sets; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModel; import com.intellij.openapi.projectRoots.SdkModificator; @@ -34,7 +36,10 @@ import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Comparing; -import com.intellij.remotesdk.RemoteCredentials; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.remote.RemoteCredentials; import com.intellij.ui.*; import com.intellij.ui.components.JBList; import com.intellij.util.NullableConsumer; @@ -43,7 +48,6 @@ import com.intellij.util.containers.FactoryMap; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import com.jetbrains.python.sdk.*; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; -import icons.PythonIcons; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -72,9 +76,10 @@ public class PythonSdkDetailsDialog extends DialogWrapper { private boolean myShowOtherProjectVirtualenvs = true; private final Module myModule; private NullableConsumer<Sdk> myShowMoreCallback; + private SdkModel.Listener myListener; public PythonSdkDetailsDialog(Project project, NullableConsumer<Sdk> showMoreCallback) { - super(project); + super(project, true); myModule = null; setTitle("Project Interpreters"); @@ -86,6 +91,12 @@ public class PythonSdkDetailsDialog extends DialogWrapper { updateOkButton(); } + @Override + protected void dispose() { + myProjectSdksModel.removeListener(myListener); + super.dispose(); + } + public PythonSdkDetailsDialog(Module module, NullableConsumer<Sdk> showMoreCallback) { super(module.getProject()); myModule = module; @@ -130,8 +141,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper { } }) .addExtraAction(new ToggleVirtualEnvFilterButton()) - .addExtraAction(new ShowPathButton()) - .addExtraAction(new GenerateSkeletonsButton()); + .addExtraAction(new ShowPathButton()); decorator.setPreferredSize(new Dimension(600, 500)); myMainPanel = decorator.createPanel(); @@ -141,7 +151,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper { } private void addListeners() { - myProjectSdksModel.addListener(new SdkModel.Listener() { + myListener = new SdkModel.Listener() { @Override public void sdkAdded(Sdk sdk) { } @@ -158,7 +168,8 @@ public class PythonSdkDetailsDialog extends DialogWrapper { @Override public void sdkHomeSelected(Sdk sdk, String newSdkHome) { } - }); + }; + myProjectSdksModel.addListener(myListener); mySdkList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent event) { updateOkButton(); @@ -223,7 +234,6 @@ public class PythonSdkDetailsDialog extends DialogWrapper { if (!myShowOtherProjectVirtualenvs) { VirtualEnvProjectFilter.removeNotMatching(myProject, pythonSdks); } - Collections.sort(pythonSdks, new PreferredSdkComparator()); //noinspection unchecked mySdkList.setModel(new CollectionListModel<Sdk>(pythonSdks)); @@ -247,17 +257,20 @@ public class PythonSdkDetailsDialog extends DialogWrapper { private void addSdk(AnActionButton button) { PythonSdkDetailsStep - .show(myProject, myProjectSdksModel.getSdks(), this, myMainPanel, button.getPreferredPopupPoint().getScreenPoint(), false, + .show(myProject, myProjectSdksModel.getSdks(), null, myMainPanel, button.getPreferredPopupPoint().getScreenPoint(), new NullableConsumer<Sdk>() { @Override public void consume(Sdk sdk) { - addCreatedSdk(sdk, false); + addCreatedSdk(sdk, true); } }); } private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv) { if (sdk != null) { + final PyRemovedSdkService sdkService = PyRemovedSdkService.getInstance(); + sdkService.restoreSdk(sdk); + boolean isVirtualEnv = PythonSdkType.isVirtualEnv(sdk); if (isVirtualEnv && !newVirtualEnv) { AddVEnvOptionsDialog dialog = new AddVEnvOptionsDialog(myMainPanel); @@ -366,13 +379,15 @@ public class PythonSdkDetailsDialog extends DialogWrapper { } private void removeSdk() { - final Sdk current_sdk = getSelectedSdk(); - if (current_sdk != null) { - myProjectSdksModel.removeSdk(current_sdk); - if (myModificators.containsKey(current_sdk)) { - SdkModificator modificator = myModificators.get(current_sdk); + final Sdk currentSdk = getSelectedSdk(); + if (currentSdk != null) { + final PyRemovedSdkService sdkService = PyRemovedSdkService.getInstance(); + sdkService.removeSdk(currentSdk); + myProjectSdksModel.removeSdk(currentSdk); + if (myModificators.containsKey(currentSdk)) { + SdkModificator modificator = myModificators.get(currentSdk); myModifiedModificators.remove(modificator); - myModificators.remove(current_sdk); + myModificators.remove(currentSdk); } refreshSdkList(); mySdkListChanged = true; @@ -420,7 +435,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper { @Override public boolean isEnabled() { - return !(getSelectedSdk() instanceof PyDetectedSdk); + return getSelectedSdk() != null; } @Override @@ -438,7 +453,17 @@ public class PythonSdkDetailsDialog extends DialogWrapper { component.setPreferredSize(new Dimension(600, 400)); component.setBorder(IdeBorderFactory.createBorder(SideBorder.ALL)); dialog.setCenterPanel(component); - final Sdk sdk = getSelectedSdk(); + Sdk sdk = getSelectedSdk(); + if (sdk instanceof PyDetectedSdk) { + final String sdkName = sdk.getName(); + VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() { + @Override + public VirtualFile compute() { + return LocalFileSystem.getInstance().refreshAndFindFileByPath(sdkName); + } + }); + sdk = SdkConfigurationUtil.setupSdk(ProjectJdkTable.getInstance().getAllJdks(), sdkHome, PythonSdkType.getInstance(), true, null, null); + } editor.reload(sdk != null ? sdk.getSdkModificator(): null); dialog.setTitle("Interpreter Paths"); @@ -446,36 +471,4 @@ public class PythonSdkDetailsDialog extends DialogWrapper { updateOkButton(); } } - - private class GenerateSkeletonsButton extends AnActionButton implements DumbAware { - public GenerateSkeletonsButton() { - super("Generate skeletons for the selected interpreter", PythonIcons.Python.Skeleton); - } - - @Override - public boolean isEnabled() { - return (getSelectedSdk() instanceof PyDetectedSdk); - } - - @Override - public void actionPerformed(AnActionEvent e) { - final Sdk sdk = getSelectedSdk(); - if (sdk instanceof PyDetectedSdk) { - try { - myProjectSdksModel.apply(); - } - catch (ConfigurationException ignored) { - } - - final Sdk addedSdk = SdkConfigurationUtil.setupSdk(myProjectSdksModel.getSdks(), sdk.getHomeDirectory(), - PythonSdkType.getInstance(), true, - null, null); - myProjectSdksModel.addSdk(addedSdk); - myProjectSdksModel.removeSdk(sdk); - refreshSdkList(); - mySdkList.setSelectedValue(addedSdk, true); - updateOkButton(); - } - } - } } diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java index 8ee900ae3e75..fc639713d965 100644 --- a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java +++ b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java @@ -26,7 +26,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.platform.DirectoryProjectGenerator; import com.intellij.platform.NewDirectoryProjectDialog; -import com.intellij.remotesdk.RemoteSdkCredentials; +import com.intellij.remote.RemoteSdkCredentials; import com.intellij.ui.ComboboxWithBrowseButton; import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.JBLabel; diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index 02176e32c287..a667bb69f849 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -89,7 +89,7 @@ public class PyJavaClassType implements PyClassLikeType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; // TODO: JDK's types could be considered built-in. } @@ -104,7 +104,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context) { if (myDefinition) { return new PyJavaClassType(myClass, false); } @@ -113,6 +113,12 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + return getReturnType(context); + } + + @Nullable + @Override public List<PyCallableParameter> getParameters(@NotNull TypeEvalContext context) { return null; } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index dbcc7e2fc8c9..6f0fd48e8742 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -52,12 +52,18 @@ public class PyJavaMethodType implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context) { return PyJavaTypeProvider.asPyType(myMethod.getReturnType()); } @Nullable @Override + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + return getReturnType(context); + } + + @Nullable + @Override public List<PyCallableParameter> getParameters(@NotNull TypeEvalContext context) { return null; } @@ -84,7 +90,7 @@ public class PyJavaMethodType implements PyCallableType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java index 2948f2108abb..6f891c02c1c4 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java @@ -31,7 +31,6 @@ import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.types.PyType; -import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -96,7 +95,7 @@ public class PyJavaPackageType implements PyType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/psi-api/src/com/jetbrains/python/PythonFileType.java b/python/psi-api/src/com/jetbrains/python/PythonFileType.java index d940be65f732..d3d78c5ab98f 100644 --- a/python/psi-api/src/com/jetbrains/python/PythonFileType.java +++ b/python/psi-api/src/com/jetbrains/python/PythonFileType.java @@ -16,11 +16,15 @@ package com.jetbrains.python; import com.intellij.lang.Language; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; import icons.PythonPsiApiIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,6 +45,7 @@ import java.util.regex.Pattern; */ public class PythonFileType extends LanguageFileType { private static final Pattern ENCODING_PATTERN = Pattern.compile("coding[:=]\\s*([-\\w.]+)"); + public static final int MAX_CHARSET_ENCODING_LINE = 2; public static PythonFileType INSTANCE = new PythonFileType(); @@ -100,14 +105,28 @@ public class PythonFileType extends LanguageFileType { } @Nullable - public static String getCharsetFromEncodingDeclaration(String content) { + public static String getCharsetFromEncodingDeclaration(@NotNull PsiFile file) { + final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); + final String content; + if (document != null && document.getLineCount() > MAX_CHARSET_ENCODING_LINE) { + final int offset = document.getLineEndOffset(MAX_CHARSET_ENCODING_LINE); + content = document.getText(TextRange.create(0, offset)); + } + else { + content = file.getText(); + } + return getCharsetFromEncodingDeclaration(content); + } + + @Nullable + private static String getCharsetFromEncodingDeclaration(@Nullable String content) { if (content == null || content.isEmpty()) { return null; } try { final BufferedReader reader = new BufferedReader(new StringReader(content)); try { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < MAX_CHARSET_ENCODING_LINE; i++) { final String line = reader.readLine(); if (line == null) { return null; diff --git a/python/psi-api/src/com/jetbrains/python/psi/Callable.java b/python/psi-api/src/com/jetbrains/python/psi/Callable.java index 23a5ef7870b7..a31197ec60c1 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java @@ -20,6 +20,8 @@ import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + /** * Something that can be called, passed parameters to, and return something back. @@ -34,10 +36,24 @@ public interface Callable extends PyTypedElement, PyQualifiedNameOwner { PyParameterList getParameterList(); /** - * @return the type of returned value. + * Returns the return type of the callable independent of a call site. + */ + @Nullable + PyType getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key); + + /** + * Returns the type of the call to the callable. + */ + @Nullable + PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite); + + /** + * Returns the type of the call to the callable where the call site is specified by the optional receiver and the arguments to parameters + * mapping. */ @Nullable - PyType getReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite); + PyType getCallType(@Nullable PyExpression receiver, @NotNull Map<PyExpression, PyNamedParameter> parameters, + @NotNull TypeEvalContext context); /** * @return a methods returns itself, non-method callables return null. diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyArgumentList.java b/python/psi-api/src/com/jetbrains/python/psi/PyArgumentList.java index 5ba21bf90556..f89f25fdf2d2 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyArgumentList.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyArgumentList.java @@ -20,6 +20,8 @@ import com.jetbrains.python.psi.resolve.PyResolveContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; + /** * Represents an argument list of a function call. * @@ -27,6 +29,12 @@ import org.jetbrains.annotations.Nullable; */ public interface PyArgumentList extends PyElement { + /** + * @return all argument list param expressions (keyword argument or nameless) + */ + @NotNull + Collection<PyExpression> getArgumentExpressions(); + @NotNull PyExpression[] getArguments(); diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java index 657a54f78299..a988714c144a 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java @@ -32,6 +32,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Map; /** * Represents a class declaration in source. @@ -113,6 +114,13 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine PyFunction[] getMethods(); /** + * Get class properties. + * @return Map [property_name] = [{@link com.jetbrains.python.psi.Property}] + */ + @NotNull + Map<String, Property> getProperties(); + + /** * Finds a method with given name. * @param name what to look for * @param inherited true: search in superclasses; false: only look for methods defined in this class. diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java index ff188f56c262..5707005026cb 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java +++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java @@ -39,7 +39,10 @@ public interface PyTypeProvider { PyType getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context); @Nullable - PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context); + PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context); + + @Nullable + PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context); @Nullable PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context); diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java index 43261ddba84e..66fb827babe4 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java @@ -34,14 +34,19 @@ public interface PyCallableType extends PyType { boolean isCallable(); /** - * Returns the type which is the result of calling an instance of this type. + * Returns the return type of a function independent of a call site. * - * @return the call result type or null if invalid. + * For example, it may return a generic type. * @param context - * @param callSite */ @Nullable - PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite); + PyType getReturnType(@NotNull TypeEvalContext context); + + /** + * Returns the type which is the result of calling an instance of this type. + */ + @Nullable + PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite); /** * Returns the list of parameter types. diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java index 098761020989..67ba765bbf81 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java @@ -73,9 +73,8 @@ public interface PyType { /** * @return true if the type is a known built-in type. - * @param context */ - boolean isBuiltin(TypeEvalContext context); + boolean isBuiltin(); void assertValid(String message); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java index 6330c4a76a17..c27dc4bc04ed 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java @@ -94,8 +94,14 @@ public class PyTypeProviderBase implements PyTypeProvider { return null; } + @Nullable + @Override + public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + return null; + } + @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { ReturnTypeDescriptor descriptor; synchronized (myMethodToReturnTypeMap) { descriptor = myMethodToReturnTypeMap.get(function.getName()); diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java index bc53ffdeceaf..f3c688bc88ae 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java @@ -18,6 +18,7 @@ package com.jetbrains.python.psi.types; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.jetbrains.python.psi.Callable; import com.jetbrains.python.psi.PyTypedElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,12 +42,19 @@ public class TypeEvalContext { @Nullable private final PsiFile myOrigin; private final Map<PyTypedElement, PyType> myEvaluated = new HashMap<PyTypedElement, PyType>(); + private final Map<Callable, PyType> myEvaluatedReturn = new HashMap<Callable, PyType>(); private final ThreadLocal<Set<PyTypedElement>> myEvaluating = new ThreadLocal<Set<PyTypedElement>>() { @Override protected Set<PyTypedElement> initialValue() { return new HashSet<PyTypedElement>(); } }; + private final ThreadLocal<Set<Callable>> myEvaluatingReturn = new ThreadLocal<Set<Callable>>() { + @Override + protected Set<Callable> initialValue() { + return new HashSet<Callable>(); + } + }; private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, @Nullable PsiFile origin) { myAllowDataFlow = allowDataFlow; @@ -114,64 +122,93 @@ public class TypeEvalContext { } return this; } - + public void trace(String message, Object... args) { if (myTrace != null) { myTrace.add(myTraceIndent + String.format(message, args)); } } - + public void traceIndent() { if (myTrace != null) { myTraceIndent += " "; } } - + public void traceUnindent() { if (myTrace != null && myTraceIndent.length() >= 2) { myTraceIndent = myTraceIndent.substring(0, myTraceIndent.length()-2); } } - + public String printTrace() { return StringUtil.join(myTrace, "\n"); } - + public boolean tracing() { return myTrace != null; } @Nullable - public PyType getType(@NotNull PyTypedElement element) { - synchronized (myEvaluated) { - if (myEvaluated.containsKey(element)) { - final PyType pyType = myEvaluated.get(element); - if (pyType != null) { - pyType.assertValid(element.toString()); - } - return pyType; - } - } + public PyType getType(@NotNull final PyTypedElement element) { final Set<PyTypedElement> evaluating = myEvaluating.get(); if (evaluating.contains(element)) { return null; } evaluating.add(element); try { - PyType result = element.getType(this, Key.INSTANCE); - if (result != null) { - result.assertValid(element.toString()); + synchronized (myEvaluated) { + if (myEvaluated.containsKey(element)) { + final PyType type = myEvaluated.get(element); + assertValid(type, element); + return type; + } } + final PyType type = element.getType(this, Key.INSTANCE); + assertValid(type, element); synchronized (myEvaluated) { - myEvaluated.put(element, result); + myEvaluated.put(element, type); } - return result; + return type; } finally { evaluating.remove(element); } } + @Nullable + public PyType getReturnType(@NotNull final Callable callable) { + final Set<Callable> evaluating = myEvaluatingReturn.get(); + if (evaluating.contains(callable)) { + return null; + } + evaluating.add(callable); + try { + synchronized (myEvaluatedReturn) { + if (myEvaluatedReturn.containsKey(callable)) { + final PyType type = myEvaluatedReturn.get(callable); + assertValid(type, callable); + return type; + } + } + final PyType type = callable.getReturnType(this, Key.INSTANCE); + assertValid(type, callable); + synchronized (myEvaluatedReturn) { + myEvaluatedReturn.put(callable, type); + } + return type; + } + finally { + evaluating.remove(callable); + } + } + + private static void assertValid(@Nullable PyType result, @NotNull PyTypedElement element) { + if (result != null) { + result.assertValid(element.toString()); + } + } + public boolean maySwitchToAST(@NotNull PsiElement element) { return myAllowStubToAST || myOrigin == element.getContainingFile(); } diff --git a/python/resources/icons/com/jetbrains/python/skeleton.png b/python/resources/icons/com/jetbrains/python/skeleton.png Binary files differdeleted file mode 100644 index b77c54ca92f8..000000000000 --- a/python/resources/icons/com/jetbrains/python/skeleton.png +++ /dev/null diff --git a/python/resources/icons/com/jetbrains/python/skeleton@2x.png b/python/resources/icons/com/jetbrains/python/skeleton@2x.png Binary files differdeleted file mode 100644 index 313b0249fffa..000000000000 --- a/python/resources/icons/com/jetbrains/python/skeleton@2x.png +++ /dev/null diff --git a/python/resources/icons/com/jetbrains/python/templateRoot.png b/python/resources/icons/com/jetbrains/python/templateRoot.png Binary files differindex a736036d6426..32d4880ec454 100644 --- a/python/resources/icons/com/jetbrains/python/templateRoot.png +++ b/python/resources/icons/com/jetbrains/python/templateRoot.png diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index e4029126ddb8..35a7e0b37775 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -372,6 +372,8 @@ serviceImplementation="com.jetbrains.python.codeInsight.PyCodeInsightSettings"/> <applicationService serviceInterface="com.jetbrains.python.testing.PyTestFrameworkService" serviceImplementation="com.jetbrains.python.testing.PyTestFrameworkService"/> + <applicationService serviceInterface="com.jetbrains.python.configuration.PyRemovedSdkService" + serviceImplementation="com.jetbrains.python.configuration.PyRemovedSdkService"/> <autoImportOptionsProvider instance="com.jetbrains.python.codeInsight.imports.PyAutoImportOptions"/> <defaultLiveTemplatesProvider implementation="com.jetbrains.python.codeInsight.liveTemplates.PyDefaultLiveTemplatesProvider"/> diff --git a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java index 1048e53b5682..27207ab31136 100644 --- a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java +++ b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java @@ -67,7 +67,7 @@ public class NumpyDocStringTypeProvider extends PyTypeProviderBase { @Nullable @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { if (isInsideNumPy(function)) { final NumPyDocString docString = NumPyDocString.forFunction(function, callSite); if (docString != null) { diff --git a/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java b/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java index d9d030c352cd..a57a4a528e0c 100644 --- a/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java +++ b/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java @@ -15,12 +15,11 @@ */ package com.jetbrains.pyqt; +import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.Callable; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.PyQualifiedExpression; -import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.stubs.PyClassNameIndex; import com.jetbrains.python.psi.types.PyClassTypeImpl; import com.jetbrains.python.psi.types.PyType; @@ -37,8 +36,9 @@ public class PyQtTypeProvider extends PyTypeProviderBase { private static final String ourQt4Signal = "pyqtSignal"; @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { - if (PyNames.INIT.equals(function.getName())) { + public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + if (PyNames.INIT.equals(callable.getName()) && callable instanceof PyFunction) { + final PyFunction function = (PyFunction)callable; final PyClass containingClass = function.getContainingClass(); if (containingClass != null && ourQt4Signal.equals(containingClass.getName())) { final String classQName = containingClass.getQualifiedName(); diff --git a/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java b/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java index f30febe2988d..15b29c1c584a 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java +++ b/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.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. @@ -82,8 +82,7 @@ public class PyMethodNameTypedHandler extends TypedHandlerDelegate { if (caretOffset == chars.length() || chars.charAt(caretOffset) != ':') { textToType += ':'; } - EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(editor, textToType, true); - editor.getCaretModel().moveToOffset(offset + 1 + pname.length()); // right after param name + EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, textToType, true, 1 + pname.length()); // right after param name return Result.STOP; } } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java index cc7817fdf3d2..d7b1598f39a6 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java @@ -131,7 +131,7 @@ public class PyDictKeyNamesCompletionContributor extends CompletionContributor { if ("dict".equals(name)) { final TypeEvalContext context = TypeEvalContext.userInitiated(callee.getContainingFile()); final PyType type = context.getType(dictConstructor); - if (type != null && type.isBuiltin(context)) { + if (type != null && type.isBuiltin()) { final PyArgumentList list = dictConstructor.getArgumentList(); if (list == null) return; final PyExpression[] argumentList = list.getArguments(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java index 322a31b6419c..8a72aa233dc5 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java @@ -58,7 +58,7 @@ public class PyDictConstructorToLiteralFormIntention extends BaseIntentionAction if (expression != null && expression.isCalleeText("dict")) { final TypeEvalContext context = TypeEvalContext.codeAnalysis(file); PyType type = context.getType(expression); - if (type != null && type.isBuiltin(context)) { + if (type != null && type.isBuiltin()) { PyExpression[] argumentList = expression.getArguments(); for (PyExpression argument : argumentList) { if (!(argument instanceof PyKeywordArgument)) return false; diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index 8783a7a16b58..39222b0fef9b 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -225,7 +225,7 @@ public class PyOverrideImplementUtil { statementBody.append(PyNames.PASS); } else { - if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getReturnType(context, null) != PyNoneType.INSTANCE) { + if (!PyNames.INIT.equals(baseFunction.getName()) && context.getReturnType(baseFunction) != PyNoneType.INSTANCE) { statementBody.append("return "); } if (baseClass.isNewStyleClass()) { diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index 9ffb86d2b090..ad1d6a24bdc1 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -89,13 +89,13 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { if (myDefinitionLevel > 0) { return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, myDefinitionLevel-1); } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 9cdf4c30994a..d7678c2cd871 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -120,7 +120,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { @Nullable @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { final String qname = getQualifiedName(function, callSite); if (qname != null) { if (OPEN_FUNCTIONS.contains(qname) && callSite != null) { diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java index b900e28f93c0..6fa6529f3dfc 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java @@ -42,11 +42,12 @@ public class PyUserSkeletonsTypeProvider extends PyTypeProviderBase { return null; } + @Nullable @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { - final PyFunction functionSkeleton = PyUserSkeletonsUtil.getUserSkeleton(function); - if (functionSkeleton != null) { - return functionSkeleton.getReturnType(context, callSite); + public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + final Callable callableSkeleton = PyUserSkeletonsUtil.getUserSkeleton(callable); + if (callableSkeleton != null) { + return context.getReturnType(callableSkeleton); } return null; } diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form index b6a71ee6ef38..5aacd414fb03 100644 --- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form +++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.configuration.PyIntegratedToolsConfigurable"> - <grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="9" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="8" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <xy x="20" y="20" width="657" height="302"/> @@ -24,12 +24,12 @@ </component> <vspacer id="fc19e"> <constraints> - <grid row="8" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + <grid row="7" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> </vspacer> <grid id="728f8" binding="myErrorPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> <constraints> - <grid row="7" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + <grid row="6" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> <border type="none"/> @@ -52,7 +52,7 @@ <grid id="e7a5f" binding="myDocStringsPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <grid row="3" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + <grid row="2" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> <border type="none"/> @@ -87,7 +87,7 @@ <grid id="9f040" binding="myRestPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <grid row="5" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + <grid row="4" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> <border type="none"/> @@ -117,20 +117,6 @@ </component> </children> </grid> - <component id="a95d2" class="javax.swing.JComboBox" binding="myTemplateLanguage"> - <constraints> - <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties/> - </component> - <component id="36fa5" class="javax.swing.JLabel"> - <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Template language:"/> - </properties> - </component> </children> </grid> </form> diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java index 63d88c837d76..838839ffcf63 100644 --- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java +++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java @@ -54,7 +54,6 @@ import com.jetbrains.python.documentation.DocStringFormat; import com.jetbrains.python.documentation.PyDocumentationSettings; import com.jetbrains.python.packaging.*; import com.jetbrains.python.sdk.PythonSdkType; -import com.jetbrains.python.templateLanguages.TemplatesService; import com.jetbrains.python.testing.PythonTestConfigurationsModel; import com.jetbrains.python.testing.TestRunnerService; import com.jetbrains.python.testing.VFSTestFrameworkListener; @@ -63,7 +62,6 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -85,9 +83,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No private JCheckBox analyzeDoctest; private JPanel myDocStringsPanel; private JPanel myRestPanel; - private JComboBox myTemplateLanguage; - private TemplatesConfigurationsModel myTemplatesModel; - private TemplatesService myTemplatesService; public PyIntegratedToolsConfigurable(@NotNull Module module) { myModule = module; @@ -107,7 +102,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No myDocStringsPanel.setBorder(IdeBorderFactory.createTitledBorder("Docstrings")); myRestPanel.setBorder(IdeBorderFactory.createTitledBorder("reStructuredText")); - myTemplatesService = TemplatesService.getInstance(module); } @NotNull @@ -198,10 +192,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No myModel = new PythonTestConfigurationsModel(configurations, TestRunnerService.getInstance(myModule).getProjectConfiguration(), myModule); - List<String> templateConfigurations = TemplatesService.getAllTemplateLanguages(); - myTemplatesModel = new TemplatesConfigurationsModel(templateConfigurations, myTemplatesService); - //noinspection unchecked - myTemplateLanguage.setModel(myTemplatesModel); updateConfigurations(); initErrorValidation(); return myMainPanel; @@ -231,9 +221,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No if (!getRequirementsPath().equals(myRequirementsPathField.getText())) { return true; } - if (myTemplateLanguage.getSelectedItem() != myTemplatesModel.getTemplateLanguage()) { - return true; - } return false; } @@ -242,11 +229,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No if (!Comparing.equal(myDocstringFormatComboBox.getSelectedItem(), myDocumentationSettings.myDocStringFormat)) { DaemonCodeAnalyzer.getInstance(myProject).restart(); } - if (myTemplateLanguage.getSelectedItem() != myTemplatesModel.getTemplateLanguage()) { - myTemplatesModel.apply(); - reparseFiles(Arrays.asList("html", "xml", "js")); //TODO: get from file extensions - } - if (analyzeDoctest.isSelected() != myDocumentationSettings.analyzeDoctest) { final List<VirtualFile> files = Lists.newArrayList(); ProjectRootManager.getInstance(myProject).getFileIndex().iterateContent(new ContentIterator() { @@ -315,9 +297,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No txtIsRst.setSelected(ReSTService.getInstance(myModule).txtIsRst()); analyzeDoctest.setSelected(myDocumentationSettings.analyzeDoctest); myRequirementsPathField.setText(getRequirementsPath()); - myTemplateLanguage.setSelectedItem(myTemplatesModel.getTemplateLanguage()); - myTemplatesModel.reset(); - } @Override diff --git a/python/src/com/jetbrains/python/configuration/TemplatesConfigurationsModel.java b/python/src/com/jetbrains/python/configuration/TemplatesConfigurationsModel.java deleted file mode 100644 index 0722b36308e7..000000000000 --- a/python/src/com/jetbrains/python/configuration/TemplatesConfigurationsModel.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.jetbrains.python.configuration; - -import com.intellij.ui.CollectionComboBoxModel; -import com.jetbrains.python.templateLanguages.TemplatesService; - -import java.util.List; - -/** - * User: catherine - */ -public class TemplatesConfigurationsModel extends CollectionComboBoxModel { - private String myTemplateLanguage; - private final TemplatesService myTemplatesService; - - public TemplatesConfigurationsModel(final List items, TemplatesService templatesService) { - super(items, templatesService.getTemplateLanguage()); - myTemplatesService = templatesService; - myTemplateLanguage = myTemplatesService.getTemplateLanguage(); - } - - public void reset() { - setSelectedItem(myTemplateLanguage); - } - - public void apply() { - myTemplateLanguage = (String)getSelectedItem(); - myTemplatesService.setTemplateLanguage(myTemplateLanguage); - } - - public Object getTemplateLanguage() { - return myTemplateLanguage; - } -}
\ No newline at end of file diff --git a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java index b4d83600b7b9..8ef4ec9a47a4 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java @@ -137,13 +137,15 @@ public class PydevConsoleExecuteActionHandler extends ProcessBackedConsoleExecut // multiline strings handling if (myInMultilineStringState != null) { - if (PyConsoleUtil.isDoubleQuoteMultilineStarts(line)) { + if (PyConsoleUtil.isDoubleQuoteMultilineStarts(line) || PyConsoleUtil.isSingleQuoteMultilineStarts(line)) { myInMultilineStringState = null; // restore language console.setLanguage(PythonLanguage.getInstance()); console.setPrompt(PyConsoleUtil.ORDINARY_PROMPT); - } - else { + } else { + if(line.equals("\n")) { + myInputBuffer.append("\n"); + } return; } } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java index 213f63511eb6..c3f89cd0cd57 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java @@ -54,8 +54,8 @@ import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.tree.FileElement; -import com.intellij.remotesdk.RemoteSdkCredentials; -import com.intellij.remotesdk.RemoteSshProcess; +import com.intellij.remote.RemoteSdkCredentials; +import com.intellij.remote.RemoteSshProcess; import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.IJSwingUtilities; diff --git a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java index 9c610e768b28..728056cca301 100644 --- a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java +++ b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java @@ -221,7 +221,7 @@ public class RunPythonConsoleAction extends AnAction implements DumbAware { final String path = Joiner.on(", ").join(Collections2.transform(pythonPath, new Function<String, String>() { @Override public String apply(String input) { - return "'" + input.replace("\\", "\\\\") + "'"; + return "'" + input.replace("\\", "\\\\").replace("'", "\\'") + "'"; } })); diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index 312db25573c8..0bae7af19732 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -34,7 +34,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; -import com.intellij.remotesdk.RemoteProcessHandlerBase; +import com.intellij.remote.RemoteProcessHandlerBase; import com.intellij.xdebugger.*; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XBreakpointHandler; diff --git a/python/src/com/jetbrains/python/debugger/PySmartStepIntoHandler.java b/python/src/com/jetbrains/python/debugger/PySmartStepIntoHandler.java index af8b69f3b07e..5b1217072465 100644 --- a/python/src/com/jetbrains/python/debugger/PySmartStepIntoHandler.java +++ b/python/src/com/jetbrains/python/debugger/PySmartStepIntoHandler.java @@ -49,6 +49,7 @@ public class PySmartStepIntoHandler extends XSmartStepIntoHandler<PySmartStepInt myProcess = process; } + @Override @NotNull public List<PySmartStepIntoVariant> computeSmartStepVariants(@NotNull XSourcePosition position) { final Document document = FileDocumentManager.getInstance().getDocument(position.getFile()); @@ -57,6 +58,7 @@ public class PySmartStepIntoHandler extends XSmartStepIntoHandler<PySmartStepInt final int line = position.getLine(); XDebuggerUtil.getInstance().iterateLine(mySession.getProject(), document, line, new Processor<PsiElement>() { + @Override public boolean process(PsiElement psiElement) { addVariants(document, line, psiElement, variants, visitedCalls); return true; @@ -67,10 +69,11 @@ public class PySmartStepIntoHandler extends XSmartStepIntoHandler<PySmartStepInt } @Override - public void startStepInto(PySmartStepIntoVariant smartStepIntoVariant) { + public void startStepInto(@NotNull PySmartStepIntoVariant smartStepIntoVariant) { myProcess.startSmartStepInto(smartStepIntoVariant.getFunctionName()); } + @Override public String getPopupTitle(@NotNull XSourcePosition position) { return PyBundle.message("debug.popup.title.step.into.function"); } diff --git a/python/src/com/jetbrains/python/debugger/PyStackFrame.java b/python/src/com/jetbrains/python/debugger/PyStackFrame.java index 1c72e8b9e0d8..2c8727c12354 100644 --- a/python/src/com/jetbrains/python/debugger/PyStackFrame.java +++ b/python/src/com/jetbrains/python/debugger/PyStackFrame.java @@ -69,7 +69,7 @@ public class PyStackFrame extends XStackFrame { } @Override - public void customizePresentation(ColoredTextContainer component) { + public void customizePresentation(@NotNull ColoredTextContainer component) { component.setIcon(AllIcons.Debugger.StackFrame); if (myPosition == null) { diff --git a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java index ad1fa2d7f5a2..6934a37d723f 100644 --- a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java @@ -226,7 +226,7 @@ public class PyTypeModelBuilder { parameterModels.add(new ParamType(parameter.getName(), build(parameter.getType(myContext), true))); } } - final PyType ret = type.getCallType(myContext, null); + final PyType ret = type.getReturnType(myContext); final TypeModel returnType = build(ret, true); return new FunctionType(returnType, parameterModels); } diff --git a/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java b/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java index 78d9d654ef77..82f2605ec5d8 100644 --- a/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java +++ b/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java @@ -99,6 +99,6 @@ public class PyFindUsagesHandlerFactory extends FindUsagesHandlerFactory { return false; } return (PyNames.FAKE_OLD_BASE.equals(containingClass.getName()) || - (PyNames.OBJECT.equals(containingClass.getName()) && PyBuiltinCache.getInstance(fun).hasInBuiltins(containingClass))); + (PyNames.OBJECT.equals(containingClass.getName()) && PyBuiltinCache.getInstance(fun).isBuiltin(containingClass))); } } diff --git a/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java b/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java index 6a06f875b1b2..9b8b0891764d 100644 --- a/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java @@ -84,7 +84,7 @@ public class PyArgumentEqualDefaultInspection extends PyInspection { private static boolean hasSpecialCasedDefaults(Callable callable, PsiElement anchor) { final String name = callable.getName(); final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor); - if ("getattr".equals(name) && cache.hasInBuiltins(callable)) { + if ("getattr".equals(name) && cache.isBuiltin(callable)) { return true; } else if ("get".equals(name) || "pop".equals(name)) { diff --git a/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java b/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java index 2731f8d8fb11..4b0945d6742b 100644 --- a/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java @@ -54,7 +54,7 @@ public class PyBroadExceptionInspection extends PyInspection { public static boolean equalsException(@NotNull PyClass cls, @NotNull TypeEvalContext context) { final PyType type = context.getType(cls); - return ("Exception".equals(cls.getName()) || "BaseException".equals(cls.getName())) && type != null && type.isBuiltin(context); + return ("Exception".equals(cls.getName()) || "BaseException".equals(cls.getName())) && type != null && type.isBuiltin(); } private static class Visitor extends PyInspectionVisitor { diff --git a/python/src/com/jetbrains/python/inspections/PyByteLiteralInspection.java b/python/src/com/jetbrains/python/inspections/PyByteLiteralInspection.java index 536074e51d39..0b5c93c8dbaa 100644 --- a/python/src/com/jetbrains/python/inspections/PyByteLiteralInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyByteLiteralInspection.java @@ -75,7 +75,7 @@ public class PyByteLiteralInspection extends PyInspection { ); } - final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(file.getText()); + final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(file); try { if (charsetString != null && !Charset.forName(charsetString).equals(Charset.forName("US-ASCII"))) default_bytes = false; diff --git a/python/src/com/jetbrains/python/inspections/PyComparisonWithNoneInspection.java b/python/src/com/jetbrains/python/inspections/PyComparisonWithNoneInspection.java index 3883cd0a6f43..ec31c002a803 100644 --- a/python/src/com/jetbrains/python/inspections/PyComparisonWithNoneInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyComparisonWithNoneInspection.java @@ -64,7 +64,7 @@ public class PyComparisonWithNoneInspection extends PyInspection { PsiReference reference = node.getReference(); assert reference != null; PsiElement result = reference.resolve(); - if (result == null || PyBuiltinCache.getInstance(node).hasInBuiltins(result)) { + if (result == null || PyBuiltinCache.getInstance(node).isBuiltin(result)) { registerProblem(node, "Comparison with None performed with equality operators", new ComparisonWithNoneQuickFix()); } } diff --git a/python/src/com/jetbrains/python/inspections/PyInitNewSignatureInspection.java b/python/src/com/jetbrains/python/inspections/PyInitNewSignatureInspection.java index 6ced1d18eae1..694d7ad17611 100644 --- a/python/src/com/jetbrains/python/inspections/PyInitNewSignatureInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyInitNewSignatureInspection.java @@ -57,7 +57,7 @@ public class PyInitNewSignatureInspection extends PyInspection { if (! cls.isNewStyleClass()) return; // old-style classes don't know about __new__ PyFunction init_or_new = cls.findInitOrNew(false); // only local final PyBuiltinCache builtins = PyBuiltinCache.getInstance(cls); - if (init_or_new == null || builtins.hasInBuiltins(init_or_new.getContainingClass())) return; // nothing is overridden + if (init_or_new == null || builtins.isBuiltin(init_or_new.getContainingClass())) return; // nothing is overridden String the_other_name = PyNames.NEW.equals(init_or_new.getName()) ? PyNames.INIT : PyNames.NEW; PyFunction the_other = cls.findMethodByName(the_other_name, true); if (the_other == null || builtins.getClass("object") == the_other.getContainingClass()) return; diff --git a/python/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java b/python/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java index 58e97044c4ab..d41cfbeea3cb 100644 --- a/python/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java @@ -62,7 +62,7 @@ public class PyMandatoryEncodingInspection extends PyInspection { @Override public void visitPyFile(PyFile node) { - final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(node.getText()); + final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(node); if (charsetString == null) { TextRange tr = new TextRange(0,0); ProblemsHolder holder = getHolder(); diff --git a/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java b/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java index 71f2772dae08..acf33c542e24 100644 --- a/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java @@ -32,8 +32,6 @@ import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; - /** * User: ktisha * @@ -66,10 +64,10 @@ public class PyMethodMayBeStaticInspection extends PyInspection { final PyClass containingClass = node.getContainingClass(); if (containingClass == null) return; if (PythonUnitTestUtil.isUnitTestCaseClass(containingClass)) return; - final Collection<PsiElement> supers = PySuperMethodsSearch.search(node).findAll(); - if (!supers.isEmpty()) return; - final Collection<PyFunction> overrides = PyOverridingMethodsSearch.search(node, true).findAll(); - if (!overrides.isEmpty()) return; + final PsiElement firstSuper = PySuperMethodsSearch.search(node).findFirst(); + if (firstSuper != null) return; + final PyFunction firstOverride = PyOverridingMethodsSearch.search(node, true).findFirst(); + if (firstOverride != null) return; final PyDecoratorList decoratorList = node.getDecoratorList(); if (decoratorList != null) return; if (node.getModifier() != null) return; diff --git a/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java b/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java index 3038b64710d1..5fd0e565a6f8 100644 --- a/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java @@ -69,7 +69,7 @@ public class PyNonAsciiCharInspection extends PyInspection { if (LanguageLevel.forElement(node).isPy3K()) return; PsiFile file = node.getContainingFile(); // can't cache this in the instance, alas if (file == null) return; - final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(file.getText()); + final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(file); boolean hasNonAscii = false; diff --git a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java index f3fddbac3a8b..1b3dfc63b61f 100644 --- a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java @@ -24,7 +24,8 @@ import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; import com.intellij.util.containers.hash.HashMap; -import com.intellij.util.containers.hash.HashSet; +import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; +import com.jetbrains.python.codeInsight.dataflow.scope.Scope; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.search.PySuperMethodsSearch; import com.jetbrains.python.psi.types.PyModuleType; @@ -34,9 +35,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Collection; import java.util.Map; -import java.util.Set; import java.util.regex.Pattern; /** @@ -71,17 +70,10 @@ public class PyPep8NamingInspection extends PyInspection { public void visitPyAssignmentStatement(PyAssignmentStatement node) { final PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class, true, PyClass.class); if (function == null) return; - final Collection<PyGlobalStatement> globalStatements = PsiTreeUtil.findChildrenOfType(function, PyGlobalStatement.class); - final Set<String> globals = new HashSet<String>(); - for (PyGlobalStatement statement : globalStatements) { - final PyTargetExpression[] statementGlobals = statement.getGlobals(); - for (PyTargetExpression global : statementGlobals) { - globals.add(global.getName()); - } - } + final Scope scope = ControlFlowCache.getScope(function); for (PyExpression expression : node.getTargets()) { final String name = expression.getName(); - if (name == null || globals.contains(name)) continue; + if (name == null || scope.isGlobal(name)) continue; if (expression instanceof PyTargetExpression) { final PyExpression qualifier = ((PyTargetExpression)expression).getQualifier(); if (qualifier != null) { diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index 967e6a47c26d..27fff5602374 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -301,7 +301,9 @@ public class PyPropertyDefinitionInspection extends PyInspection { } else { PyReferenceExpression callSite = being_checked instanceof PyReferenceExpression ? (PyReferenceExpression) being_checked : null; - hasReturns = !(callable.getReturnType(myTypeEvalContext, callSite) instanceof PyNoneType); + final PyType type = callSite != null ? callable.getCallType(myTypeEvalContext, callSite) + : myTypeEvalContext.getReturnType(callable); + hasReturns = !(type instanceof PyNoneType); } if (allowed ^ hasReturns) { if (allowed && callable instanceof PyFunction) { diff --git a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java index fe9ac7f9159e..52775764074e 100644 --- a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java @@ -70,7 +70,10 @@ public class PyProtectedMemberInspection extends PyInspection { if (name != null && name.startsWith("_") && !name.startsWith("__") && !name.endsWith("__")) { final PyClass parentClass = getClassOwner(node); if (parentClass != null) { - final PsiReference reference = node.getReference(); + final PsiReference reference = node.getReference(resolveWithoutImplicits()); + if (reference == null) { + return; + } final PsiElement resolvedExpression = reference.resolve(); final PyClass resolvedClass = getClassOwner(resolvedExpression); if (parentClass.isSubclass(resolvedClass)) diff --git a/python/src/com/jetbrains/python/inspections/PySetFunctionToLiteralInspection.java b/python/src/com/jetbrains/python/inspections/PySetFunctionToLiteralInspection.java index f0bdeb399a1b..e846fdba3c19 100644 --- a/python/src/com/jetbrains/python/inspections/PySetFunctionToLiteralInspection.java +++ b/python/src/com/jetbrains/python/inspections/PySetFunctionToLiteralInspection.java @@ -22,9 +22,7 @@ import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; -import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiReference; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.inspections.quickfix.ReplaceFunctionWithSetLiteralQuickFix; @@ -66,7 +64,7 @@ public class PySetFunctionToLiteralInspection extends PyInspection { public void visitPyCallExpression(final PyCallExpression node) { if (!isAvailable(node)) return; PyExpression callee = node.getCallee(); - if (node.isCalleeText(PyNames.SET) && isInBuiltins(callee)) { + if (node.isCalleeText(PyNames.SET) && callee != null && PyBuiltinCache.isInBuiltins(callee)) { PyExpression[] arguments = node.getArguments(); if (arguments.length == 1) { PyElement[] elements = getSetCallArguments(node); @@ -91,20 +89,6 @@ public class PySetFunctionToLiteralInspection extends PyInspection { } return LanguageLevel.forElement(node).supportsSetLiterals(); } - - private static boolean isInBuiltins(PyExpression callee) { - if (callee instanceof PyQualifiedExpression && (((PyQualifiedExpression)callee).isQualified())) { - return false; - } - PsiReference reference = callee.getReference(); - if (reference != null) { - PsiElement resolved = reference.resolve(); - if (resolved != null && PyBuiltinCache.getInstance(callee).hasInBuiltins(resolved)) { - return true; - } - } - return false; - } } public static PyElement[] getSetCallArguments(PyCallExpression node) { diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java index 28ccafd5aa12..a72ec9ef8504 100644 --- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java @@ -111,7 +111,7 @@ public class PyStatementEffectInspection extends PyInspection { // maybe the op is overridden and may produce side effects, like cout << "hello" PyType type = myTypeEvalContext.getType(leftExpression); if (type != null && - !type.isBuiltin(myTypeEvalContext) && + !type.isBuiltin() && type.resolveMember(method, null, AccessDirection.READ, resolveWithoutImplicits()) != null) { return true; } @@ -119,7 +119,7 @@ public class PyStatementEffectInspection extends PyInspection { type = myTypeEvalContext.getType(rightExpression); if (type != null) { String rmethod = "__r" + method.substring(2); // __add__ -> __radd__ - if (!type.isBuiltin(myTypeEvalContext) && type.resolveMember(rmethod, null, AccessDirection.READ, resolveWithoutImplicits()) != null) { + if (!type.isBuiltin() && type.resolveMember(rmethod, null, AccessDirection.READ, resolveWithoutImplicits()) != null) { return true; } } diff --git a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java index 180fd1bfc3b0..280822ba7175 100644 --- a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java @@ -149,7 +149,7 @@ public class PyStringFormatInspection extends PyInspection { } else if (rightExpression instanceof PyCallExpression) { final Callable callable = ((PyCallExpression)rightExpression).resolveCalleeFunction(resolveContext); - // TODO: Switch to Callable.getReturnType() + // TODO: Switch to Callable.getCallType() if (callable instanceof PyFunction && myTypeEvalContext.maySwitchToAST((PyFunction) callable)) { PyStatementList statementList = ((PyFunction)callable).getStatementList(); if (statementList == null) { diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 45df382d3f83..d31d19ef4da9 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -102,7 +102,7 @@ public class PyTypeCheckerInspection extends PyInspection { } final PyType argType = myTypeEvalContext.getType(entry.getKey()); if (!genericsCollected) { - substitutions.putAll(PyTypeChecker.collectCallGenerics(results.getCallable(), results.getReceiver(), myTypeEvalContext)); + substitutions.putAll(PyTypeChecker.unifyReceiver(results.getReceiver(), myTypeEvalContext)); genericsCollected = true; } checkTypes(paramType, argType, entry.getKey(), myTypeEvalContext, substitutions); diff --git a/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java b/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java index abec5b165fb9..9e0031afec84 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java @@ -132,7 +132,7 @@ public class PyUnboundLocalVariableInspection extends PyInspection { return; } final PsiElement resolved = ref.resolve(); - final boolean isBuiltin = PyBuiltinCache.getInstance(node).hasInBuiltins(resolved); + final boolean isBuiltin = PyBuiltinCache.getInstance(node).isBuiltin(resolved); if (owner instanceof PyClass) { if (isBuiltin || ScopeUtil.getDeclarationScopeOwner(owner, name) != null) { return; diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 9e08a47eafc9..2e33a1f175b1 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -749,7 +749,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { PsiElement element = reference.getElement(); if (type instanceof PyClassTypeImpl) { PyClass cls = ((PyClassType)type).getPyClass(); - if (!PyBuiltinCache.getInstance(element).hasInBuiltins(cls)) { + if (!PyBuiltinCache.getInstance(element).isBuiltin(cls)) { if (element.getParent() instanceof PyCallExpression) { actions.add(new AddMethodQuickFix(refText, (PyClassType)type, true)); } @@ -886,7 +886,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { return true; } method = resolveClassMember(cls, PyNames.GETATTRIBUTE, context); - if (method != null && !PyBuiltinCache.getInstance(cls).hasInBuiltins(method)) { + if (method != null && !PyBuiltinCache.getInstance(cls).isBuiltin(method)) { return true; } return false; diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java index f7883535d2e6..3dc42057348f 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java @@ -328,7 +328,7 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { PyCallExpression expr = (PyCallExpression) source; if (expr.isCalleeText("range", "xrange")) { final Callable callee = expr.resolveCalleeFunction(PyResolveContext.noImplicits().withTypeEvalContext(myTypeEvalContext)); - if (callee != null && PyBuiltinCache.getInstance(forStatement).hasInBuiltins(callee)) { + if (callee != null && PyBuiltinCache.getInstance(forStatement).isBuiltin(callee)) { return true; } } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index 82a5fd9590ac..fe4ab8f910ef 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -49,8 +49,9 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; -import com.intellij.remotesdk.RemoteFile; -import com.intellij.remotesdk.RemoteSdkCredentials; +import com.intellij.remote.RemoteSdkAdditionalData; +import com.intellij.remote.RemoteFile; +import com.intellij.remote.RemoteSdkCredentials; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.SystemProperties; @@ -778,10 +779,17 @@ public class PyPackageManagerImpl extends PyPackageManager { if (homePath == null) { throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args, "Cannot find interpreter for SDK"); } - if (sdkData instanceof RemoteSdkCredentials) { //remote interpreter - final RemoteSdkCredentials remoteSdkCredentials = (RemoteSdkCredentials)sdkData; + if (sdkData instanceof RemoteSdkAdditionalData) { //remote interpreter + RemoteSdkCredentials remoteSdkCredentials; + try { + remoteSdkCredentials = ((RemoteSdkAdditionalData)sdkData).getRemoteSdkCredentials(); + } + catch (InterruptedException e) { + LOG.error(e); + remoteSdkCredentials = null; + } final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance(); - if (manager != null) { + if (manager != null && remoteSdkCredentials != null) { final List<String> cmdline = new ArrayList<String>(); cmdline.add(homePath); cmdline.add(RemoteFile.detectSystemByPath(homePath).createRemoteFile(helperPath).getPath()); diff --git a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java index d894786b7dd6..0fdbc53a5586 100644 --- a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java +++ b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java @@ -33,8 +33,8 @@ import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.sdk.flavors.IronPythonSdkFlavor; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.awt.*; import java.util.List; import java.util.Set; @@ -51,8 +51,6 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel { public PyInstalledPackagesPanel(Project project, PackagesNotificationPanel area) { super(project, area); - setPreferredSize(new Dimension(500, 500)); - myNotificationArea.addLinkHandler(INSTALL_SETUPTOOLS, new Runnable() { @Override public void run() { @@ -78,7 +76,11 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel { return service != null ? service.getSdk() : null; } - public void updateNotifications(@NotNull final Sdk selectedSdk) { + public void updateNotifications(@Nullable final Sdk selectedSdk) { + if (selectedSdk == null) { + myNotificationArea.hide(); + return; + } final Application application = ApplicationManager.getApplication(); application.executeOnPooledThread(new Runnable() { @Override diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 83036eec8626..97b380b4f381 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -857,7 +857,10 @@ public class PyUtil { * * @param elt starting point of search. * @return 'class' or 'def' element, or null if not found. + * + * @deprecated Use {@link ScopeUtil#getScopeOwner} instead. */ + @Deprecated @Nullable public static PsiElement getConcealingParent(PsiElement elt) { if (elt == null || elt instanceof PsiFile) { @@ -1138,7 +1141,7 @@ public class PyUtil { if (reference == null) return false; PsiElement resolved = reference.resolve(); PyBuiltinCache cache = PyBuiltinCache.getInstance(node); - if (resolved != null && cache.hasInBuiltins(resolved)) { + if (resolved != null && cache.isBuiltin(resolved)) { PyExpression[] args = node.getArguments(); if (args.length > 0) { String firstArg = args[0].getText(); diff --git a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java index 692ff0052b10..20e8c5dbe1dc 100644 --- a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java @@ -134,7 +134,7 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { } else { PyType arg_type = context.getType(arg); - if (arg_type != null && arg_type.isBuiltin(context) && "list".equals(arg_type.getName())) { + if (arg_type != null && arg_type.isBuiltin() && "list".equals(arg_type.getName())) { mapped_args.add(arg); // we can't really analyze arbitrary lists statically yet // but ListLiteralExpressions are handled by visitor } diff --git a/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java b/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java index dfe12ca6dc30..2e6120a29303 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java @@ -48,6 +48,23 @@ public class PyArgumentListImpl extends PyElementImpl implements PyArgumentList pyVisitor.visitPyArgumentList(this); } + @Override + @NotNull + public Collection<PyExpression> getArgumentExpressions() { + final PyExpression[] arguments = getArguments(); + final Collection<PyExpression> result = new ArrayList<PyExpression>(arguments.length); + for (final PyExpression expression : arguments) { + if (expression instanceof PyKeywordArgument) { + final PyExpression valueExpression = ((PyKeywordArgument)expression).getValueExpression(); + result.add(valueExpression); + } + if (expression instanceof PyReferenceExpression) { + result.add(expression); + } + } + return result; + } + @NotNull public PyExpression[] getArguments() { return childrenToPsi(PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens(), PyExpression.EMPTY_ARRAY); diff --git a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java index bee876ac948d..61513d1e4c4f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java @@ -137,7 +137,7 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp } final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCall(this, context); if (results != null) { - final PyType type = results.getCallable().getReturnType(context, this); + final PyType type = results.getCallable().getCallType(context, this); if (!PyTypeChecker.isUnknown(type) && !(type instanceof PyNoneType)) { return type; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java index b545290c13c6..0f4b0813cf7c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java @@ -27,15 +27,9 @@ import com.intellij.openapi.roots.impl.ModuleLibraryOrderEntryImpl; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileSystemItem; -import com.intellij.psi.PsiManager; +import com.intellij.psi.*; import com.jetbrains.python.PyNames; -import com.jetbrains.python.psi.LanguageLevel; -import com.jetbrains.python.psi.PyClass; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PySequenceExpression; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PythonSdkPathCache; import com.jetbrains.python.psi.types.*; import com.jetbrains.python.sdk.PythonSdkType; @@ -183,7 +177,13 @@ public class PyBuiltinCache { @Nullable public PsiElement getByName(@NonNls String name) { if (myBuiltinsFile != null) { - return myBuiltinsFile.getElementNamed(name); + final PsiElement element = myBuiltinsFile.getElementNamed(name); + if (element != null) { + return element; + } + } + if (myExceptionsFile != null) { + return myExceptionsFile.getElementNamed(name); } return null; } @@ -337,7 +337,7 @@ public class PyBuiltinCache { * @param target an element to check. * @return true iff target is inside the __builtins__.py */ - public boolean hasInBuiltins(@Nullable PsiElement target) { + public boolean isBuiltin(@Nullable PsiElement target) { if (target == null) return false; if (! target.isValid()) return false; final PsiFile the_file = target.getContainingFile(); @@ -347,4 +347,22 @@ public class PyBuiltinCache { // files are singletons, no need to compare URIs return the_file == myBuiltinsFile || the_file == myExceptionsFile; } + + public static boolean isInBuiltins(@NotNull PyExpression expression) { + if (expression instanceof PyQualifiedExpression && (((PyQualifiedExpression)expression).isQualified())) { + return false; + } + final String name = expression.getName(); + PsiReference reference = expression.getReference(); + if (reference != null && name != null) { + final PyBuiltinCache cache = getInstance(expression); + if (cache.getByName(name) != null) { + final PsiElement resolved = reference.resolve(); + if (resolved != null && cache.isBuiltin(resolved)) { + return true; + } + } + } + return false; + } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 781dc28c0d35..45f094764533 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -198,7 +198,7 @@ public class PyCallExpressionHelper { final PyFunction function = (PyFunction)resolved; final Property property = function.getProperty(); if (property != null && isQualifiedByInstance(function, qualifiers, context)) { - final PyType type = function.getReturnType(context, null); + final PyType type = context.getReturnType(function); if (type instanceof PyFunctionType) { resolved = ((PyFunctionType)type).getCallable(); } @@ -424,7 +424,7 @@ public class PyCallExpressionHelper { } } if (init != null) { - final PyType t = init.getReturnType(context, (PyReferenceExpression)callee); + final PyType t = init.getCallType(context, (PyReferenceExpression)callee); if (cls != null) { if (init.getContainingClass() != cls) { if (t instanceof PyCollectionType) { @@ -439,7 +439,7 @@ public class PyCallExpressionHelper { } if (cls != null && t == null) { final PyFunction newMethod = cls.findMethodByName(PyNames.NEW, true); - if (newMethod != null && !PyBuiltinCache.getInstance(call).hasInBuiltins(newMethod)) { + if (newMethod != null && !PyBuiltinCache.getInstance(call).isBuiltin(newMethod)) { return PyUnionType.createWeakType(new PyClassTypeImpl(cls, false)); } } @@ -453,7 +453,7 @@ public class PyCallExpressionHelper { } if (target instanceof Callable) { final Callable callable = (Callable)target; - return callable.getReturnType(context, (PyReferenceExpression)callee); + return callable.getCallType(context, (PyReferenceExpression)callee); } } } @@ -463,8 +463,14 @@ public class PyCallExpressionHelper { else { final PyType type = context.getType(callee); if (type instanceof PyCallableType) { + final PyCallableType callableType = (PyCallableType)type; final PyQualifiedExpression callSite = callee instanceof PyQualifiedExpression ? (PyQualifiedExpression)callee : null; - return ((PyCallableType) type).getCallType(context, callSite); + if (callSite != null) { + return callableType.getCallType(context, callSite); + } + else { + return callableType.getReturnType(context); + } } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index bea0e10312bb..eaa480be1ac7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -381,6 +381,13 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement } @Override + @NotNull + public Map<String, Property> getProperties() { + initProperties(); + return new HashMap<String, Property>(myPropertyCache); + } + + @Override public PyClass[] getNestedClasses() { return getClassChildren(TokenSet.create(PyElementTypes.CLASS_DECLARATION), PyClass.ARRAY_FACTORY); } @@ -607,9 +614,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement @Override public Property findPropertyByCallable(Callable callable) { - if (myPropertyCache == null) { - myPropertyCache = initializePropertyCache(); - } + initProperties(); for (Property property : myPropertyCache.values()) { if (property.getGetter().valueOrNull() == callable || property.getSetter().valueOrNull() == callable || @@ -621,10 +626,14 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement } private Property findLocalProperty(String name) { + initProperties(); + return myPropertyCache.get(name); + } + + private synchronized void initProperties() { if (myPropertyCache == null) { myPropertyCache = initializePropertyCache(); } - return myPropertyCache.get(name); } private Map<String, Property> initializePropertyCache() { @@ -750,7 +759,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement if (!(callable instanceof StubBasedPsiElement) && !context.maySwitchToAST(callable)) { return null; } - return callable.getReturnType(context, null); + return context.getReturnType(callable); } return null; } @@ -1149,7 +1158,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement } } final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(this); - if (result.isEmpty() && isValid() && !builtinCache.hasInBuiltins(this)) { + if (result.isEmpty() && isValid() && !builtinCache.isBuiltin(this)) { final String implicitSuperName = LanguageLevel.forElement(this).isPy3K() ? PyNames.OBJECT : PyNames.FAKE_OLD_BASE; final PyClass implicitSuper = builtinCache.getClass(implicitSuperName); if (implicitSuper != null) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java index 92e75ed21a5a..9e8ef1aa8c69 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java @@ -65,7 +65,7 @@ public class PyDecoratorImpl extends StubBasedPsiElementBase<PyDecoratorStub> im if (node != null) { PyReferenceExpression ref = (PyReferenceExpression)node.getPsi(); PsiElement target = ref.getReference().resolve(); - return PyBuiltinCache.getInstance(this).hasInBuiltins(target); + return PyBuiltinCache.getInstance(this).isBuiltin(target); } return false; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 2ffc8e6cba03..acc225b67f22 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -15,7 +15,6 @@ */ package com.jetbrains.python.psi.impl; -import com.google.common.collect.Maps; import com.intellij.lang.ASTNode; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pair; @@ -176,42 +175,74 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - PyType type = getGenericReturnType(context, callSite); - if (callSite == null) { - return type; + public PyType getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { + for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { + final PyType returnType = typeProvider.getReturnType(this, context); + if (returnType != null) { + returnType.assertValid(typeProvider.toString()); + return returnType; + } } - final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, context); - if (PyTypeChecker.hasGenerics(type, context)) { - if (results != null) { - final Map<PyGenericType, PyType> substitutions = PyTypeChecker.unifyGenericCall(this, results.getReceiver(), results.getArguments(), - context); - type = substitutions != null ? PyTypeChecker.substitute(type, substitutions, context) : null; + if (context.maySwitchToAST(this) && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) { + PyAnnotation anno = getAnnotation(); + if (anno != null) { + PyClass pyClass = anno.resolveToClass(); + if (pyClass != null) { + return new PyClassTypeImpl(pyClass, false); + } } - else { - type = null; + } + final PyType docStringType = getReturnTypeFromDocString(); + if (docStringType != null) { + docStringType.assertValid("from docstring"); + return docStringType; + } + if (context.allowReturnTypes(this)) { + final Ref<? extends PyType> yieldTypeRef = getYieldStatementType(context); + if (yieldTypeRef != null) { + return yieldTypeRef.get(); } + return getReturnStatementType(context); } - if (results != null) { - type = replaceSelf(type, results.getReceiver(), context); + return null; + } + + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + PyType type = null; + for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { + type = typeProvider.getCallType(this, callSite, context); + if (type != null) { + type.assertValid(typeProvider.toString()); + break; + } } - if (results != null && isDynamicallyEvaluated(results.getArguments().values(), context)) { - return PyUnionType.createWeakType(type); + if (type == null) { + type = context.getReturnType(this); + } + final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, context); + if (results != null) { + return analyzeCallType(type, results.getReceiver(), results.getArguments(), context); } return type; } @Nullable - /** - * Suits when there is no call site(e.g. implicit __iter__ call in statement for) - */ - public PyType getReturnTypeWithoutCallSite(@NotNull TypeEvalContext context, - @Nullable PyExpression receiver) { - PyType type = getGenericReturnType(context, null); + @Override + public PyType getCallType(@Nullable PyExpression receiver, + @NotNull Map<PyExpression, PyNamedParameter> parameters, + @NotNull TypeEvalContext context) { + return analyzeCallType(context.getReturnType(this), receiver, parameters, context); + } + + @Nullable + private PyType analyzeCallType(@Nullable PyType type, + @Nullable PyExpression receiver, + @NotNull Map<PyExpression, PyNamedParameter> parameters, + @NotNull TypeEvalContext context) { if (PyTypeChecker.hasGenerics(type, context)) { - final Map<PyGenericType, PyType> substitutions = PyTypeChecker.unifyGenericCall(this, receiver, - Maps.<PyExpression, PyNamedParameter>newHashMap(), - context); + final Map<PyGenericType, PyType> substitutions = PyTypeChecker.unifyGenericCall(receiver, parameters, context); if (substitutions != null) { type = PyTypeChecker.substitute(type, substitutions, context); } @@ -219,7 +250,13 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp type = null; } } - return replaceSelf(type, receiver, context); + if (receiver != null) { + type = replaceSelf(type, receiver, context); + } + if (type != null && isDynamicallyEvaluated(parameters.values(), context)) { + type = PyUnionType.createWeakType(type); + } + return type; } @Nullable @@ -250,39 +287,6 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp } @Nullable - private PyType getGenericReturnType(@NotNull TypeEvalContext typeEvalContext, @Nullable PyQualifiedExpression callSite) { - if (typeEvalContext.maySwitchToAST(this) && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) { - PyAnnotation anno = getAnnotation(); - if (anno != null) { - PyClass pyClass = anno.resolveToClass(); - if (pyClass != null) { - return new PyClassTypeImpl(pyClass, false); - } - } - } - for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { - final PyType returnType = typeProvider.getReturnType(this, callSite, typeEvalContext); - if (returnType != null) { - returnType.assertValid(typeProvider.toString()); - return returnType; - } - } - final PyType docStringType = getReturnTypeFromDocString(); - if (docStringType != null) { - docStringType.assertValid("from docstring"); - return docStringType; - } - if (typeEvalContext.allowReturnTypes(this)) { - final Ref<? extends PyType> yieldTypeRef = getYieldStatementType(typeEvalContext); - if (yieldTypeRef != null) { - return yieldTypeRef.get(); - } - return getReturnStatementType(typeEvalContext); - } - return null; - } - - @Nullable private Ref<? extends PyType> getYieldStatementType(@NotNull final TypeEvalContext context) { Ref<PyType> elementType = null; final PyBuiltinCache cache = PyBuiltinCache.getInstance(this); @@ -386,8 +390,9 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp return type; } } + final boolean hasCustomDecorators = PyUtil.hasCustomDecorators(this) && !PyUtil.isDecoratedAsAbstract(this) && getProperty() == null; final PyFunctionType type = new PyFunctionType(this); - if (getDecoratorList() != null) { + if (hasCustomDecorators) { return PyUnionType.createWeakType(type); } return type; diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index 56249f1fdfa4..0dd75915de12 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -27,6 +27,8 @@ import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + /** * @author yole */ @@ -61,10 +63,23 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyExpression body = getBody(); - if (body != null) return context.getType(body); - else return null; + return body != null ? context.getType(body) : null; + } + + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + return context.getReturnType(this); + } + + @Nullable + @Override + public PyType getCallType(@Nullable PyExpression receiver, + @NotNull Map<PyExpression, PyNamedParameter> parameters, + @NotNull TypeEvalContext context) { + return context.getReturnType(this); } @Nullable diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index 6ad33d60569e..f38937daa87f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -208,7 +208,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame PyType initType = null; final PyFunction init = containingClass.findInitOrNew(true); if (init != null && init != func) { - initType = init.getReturnType(context, null); + initType = context.getReturnType(init); if (init.getContainingClass() != containingClass) { if (initType instanceof PyCollectionType) { final PyType elementType = ((PyCollectionType)initType).getElementType(context); diff --git a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java index 71658f075451..79535f21f3f4 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java @@ -88,7 +88,7 @@ public class PyPrefixExpressionImpl extends PyElementImpl implements PyPrefixExp if (ref != null) { final PsiElement resolved = ref.resolve(); if (resolved instanceof Callable) { - return ((Callable)resolved).getReturnType(context, this); + return ((Callable)resolved).getCallType(context, this); } } return null; diff --git a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java index 61438286bb8b..2b21e17ee0f8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java @@ -71,7 +71,7 @@ public class PySubscriptionExpressionImpl extends PyElementImpl implements PySub if (ref != null) { final PsiElement resolved = ref.resolve(); if (resolved instanceof Callable) { - res = ((Callable)resolved).getReturnType(context, this); + res = ((Callable)resolved).getCallType(context, this); } } if (PyTypeChecker.isUnknown(res) || res instanceof PyNoneType) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index c56111e612f7..060c39ccdee0 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -54,6 +54,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -243,8 +244,8 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp if (exprType instanceof PyClassType) { final PyClass cls = ((PyClassType)exprType).getPyClass(); final PyFunction enter = cls.findMethodByName(PyNames.ENTER, true); - if (enter instanceof PyFunctionImpl) { - final PyType enterType = ((PyFunctionImpl)enter).getReturnTypeWithoutCallSite(context, expression); + if (enter != null) { + final PyType enterType = enter.getCallType(expression, Collections.<PyExpression, PyNamedParameter>emptyMap(), context); if (enterType != null) { return enterType; } @@ -438,10 +439,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp @Nullable private static PyType getContextSensitiveType(@NotNull PyFunction function, @NotNull TypeEvalContext context, @Nullable PyExpression source) { - if (function instanceof PyFunctionImpl) { - return ((PyFunctionImpl)function).getReturnTypeWithoutCallSite(context, source); - } - return function.getReturnType(context, null); + return function.getCallType(source, Collections.<PyExpression, PyNamedParameter>emptyMap(), context); } @Nullable diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java index e66a219062b6..a537dae722c1 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java @@ -212,7 +212,7 @@ public class PyQualifiedReference extends PyReferenceImpl { PyExpression callee = ((PyCallExpression)qualifier).getCallee(); if (callee instanceof PyReferenceExpression && PyNames.SUPER.equals(callee.getName())) { PsiElement target = ((PyReferenceExpression)callee).getReference().resolve(); - if (target != null && PyBuiltinCache.getInstance(qualifier).hasInBuiltins(target)) return false; // super() of unresolved type + if (target != null && PyBuiltinCache.getInstance(qualifier).isBuiltin(target)) return false; // super() of unresolved type } } } diff --git a/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java b/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java index 3987e4e03032..bfa402449853 100644 --- a/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java +++ b/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java @@ -124,7 +124,7 @@ public class CompletionVariantsProcessor extends VariantsProcessor { // special case hack to avoid the need of patching generator3.py PyClass containingClass = callee.getContainingClass(); if (containingClass != null && PyNames.PROPERTY.equals(containingClass.getName()) && - PyBuiltinCache.getInstance(elementInCall).hasInBuiltins(containingClass)) { + PyBuiltinCache.getInstance(elementInCall).isBuiltin(containingClass)) { return true; } diff --git a/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java b/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java index 105aec5c0f7b..f743b8ec19f2 100644 --- a/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java +++ b/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java @@ -70,11 +70,13 @@ public class PyModuleNameIndex extends ScalarIndexExtension<String> { return myDataIndexer; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(PythonFileType.INSTANCE); diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java index f417f5aa4c93..dc63784e19aa 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java @@ -49,7 +49,13 @@ public class PyCallableTypeImpl implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context) { + return myReturnType; + } + + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { return myReturnType; } @@ -105,7 +111,7 @@ public class PyCallableTypeImpl implements PyCallableType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 715421ace1cb..778b8387f85e 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -163,7 +163,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } } - if ("super".equals(getClassQName()) && isBuiltin(context) && location instanceof PyCallExpression) { + if ("super".equals(getClassQName()) && isBuiltin() && location instanceof PyCallExpression) { // methods of super() call are not of class super! PyExpression first_arg = ((PyCallExpression)location).getArgument(0, PyExpression.class); if (first_arg != null) { // the usual case: first arg is the derived class that super() is proxying for @@ -307,7 +307,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context) { if (isDefinition()) { return new PyClassTypeImpl(getPyClass(), false); } @@ -316,6 +316,12 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + return getReturnType(context); + } + + @Nullable + @Override public List<PyCallableParameter> getParameters(@NotNull TypeEvalContext context) { return null; } @@ -530,8 +536,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } @Override - public boolean isBuiltin(TypeEvalContext context) { - return PyBuiltinCache.getInstance(myClass).hasInBuiltins(myClass); + public boolean isBuiltin() { + return PyBuiltinCache.getInstance(myClass).isBuiltin(myClass); } @Override diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 5e0c35699067..229fe2677d12 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -46,8 +46,14 @@ public class PyFunctionType implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - return myCallable.getReturnType(context, callSite); + public PyType getReturnType(@NotNull TypeEvalContext context) { + return context.getReturnType(myCallable); + } + + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + return myCallable.getCallType(context, callSite); } @Nullable @@ -79,7 +85,7 @@ public class PyFunctionType implements PyCallableType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/src/com/jetbrains/python/psi/types/PyGenericType.java index af7aaae80c44..68256ae6c3f3 100644 --- a/python/src/com/jetbrains/python/psi/types/PyGenericType.java +++ b/python/src/com/jetbrains/python/psi/types/PyGenericType.java @@ -59,7 +59,7 @@ public class PyGenericType implements PyType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index 3b56b6320289..5f66c818388d 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -90,7 +90,7 @@ public class PyImportedModuleType implements PyType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; // no module can be imported from builtins } diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index 5e495cdd4a88..f58f8f879c3b 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -407,7 +407,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return true; } diff --git a/python/src/com/jetbrains/python/psi/types/PyNoneType.java b/python/src/com/jetbrains/python/psi/types/PyNoneType.java index 05a793182e57..417f0ce1a2f1 100644 --- a/python/src/com/jetbrains/python/psi/types/PyNoneType.java +++ b/python/src/com/jetbrains/python/psi/types/PyNoneType.java @@ -53,7 +53,7 @@ public class PyNoneType implements PyType { // TODO must extend ClassType. It's } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return true; } diff --git a/python/src/com/jetbrains/python/psi/types/PyTupleType.java b/python/src/com/jetbrains/python/psi/types/PyTupleType.java index 8ede14ea8c99..ae6ca00b3dbd 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTupleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyTupleType.java @@ -63,7 +63,7 @@ public class PyTupleType extends PyClassTypeImpl implements PySubscriptableType } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return true; } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 632633bc6501..cbdeb163e923 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -20,7 +20,6 @@ import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; import com.intellij.psi.ResolveResult; import com.jetbrains.python.PyNames; -import com.jetbrains.python.codeInsight.stdlib.PyStdlibTypeProvider; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; @@ -172,8 +171,7 @@ public class PyTypeChecker { } } } - if (!match(expectedCallable.getCallType(context, null), actualCallable.getCallType(context, null), context, substitutions, - recursive)) { + if (!match(expectedCallable.getReturnType(context), actualCallable.getReturnType(context), context, substitutions, recursive)) { return false; } return true; @@ -259,7 +257,7 @@ public class PyTypeChecker { } } } - collectGenerics(callable.getCallType(context, null), context, collected, visited); + collectGenerics(callable.getReturnType(context), context, collected, visited); } } @@ -309,7 +307,7 @@ public class PyTypeChecker { substParams.add(subst); } } - final PyType substResult = substitute(callable.getCallType(context, null), substitutions, context); + final PyType substResult = substitute(callable.getReturnType(context), substitutions, context); return new PyCallableTypeImpl(substParams, substResult); } } @@ -317,11 +315,10 @@ public class PyTypeChecker { } @Nullable - public static Map<PyGenericType, PyType> unifyGenericCall(@NotNull PyFunction function, - @Nullable PyExpression receiver, + public static Map<PyGenericType, PyType> unifyGenericCall(@Nullable PyExpression receiver, @NotNull Map<PyExpression, PyNamedParameter> arguments, @NotNull TypeEvalContext context) { - final Map<PyGenericType, PyType> substitutions = collectCallGenerics(function, receiver, context); + final Map<PyGenericType, PyType> substitutions = unifyReceiver(receiver, context); for (Map.Entry<PyExpression, PyNamedParameter> entry : arguments.entrySet()) { final PyNamedParameter p = entry.getValue(); if (p.isPositionalContainer() || p.isKeywordContainer()) { @@ -337,8 +334,7 @@ public class PyTypeChecker { } @NotNull - public static Map<PyGenericType, PyType> collectCallGenerics(@NotNull Callable callable, @Nullable PyExpression receiver, - @NotNull TypeEvalContext context) { + public static Map<PyGenericType, PyType> unifyReceiver(@Nullable PyExpression receiver, @NotNull TypeEvalContext context) { final Map<PyGenericType, PyType> substitutions = new LinkedHashMap<PyGenericType, PyType>(); // Collect generic params of object type final Set<PyGenericType> generics = new LinkedHashSet<PyGenericType>(); @@ -347,14 +343,22 @@ public class PyTypeChecker { for (PyGenericType t : generics) { substitutions.put(t, t); } - final PyClass cls = (callable instanceof PyFunction) ? ((PyFunction)callable).getContainingClass() : null; - if (cls != null) { - final PyFunction init = cls.findInitOrNew(true); - // Unify generics in constructor - if (init != null) { - final PyType initType = init.getReturnType(context, null); - if (initType != null) { - match(initType, qualifierType, context, substitutions); + // Unify generics in constructor + if (qualifierType != null) { + final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); + // TODO: Resolve to __new__ as well + final List<? extends RatedResolveResult> results = qualifierType.resolveMember(PyNames.INIT, null, AccessDirection.READ, + resolveContext); + if (results != null && !results.isEmpty()) { + final PsiElement init = results.get(0).getElement(); + if (init instanceof PyTypedElement) { + final PyType initType = context.getType((PyTypedElement)init); + if (initType instanceof PyCallableType) { + final PyType initReturnType = ((PyCallableType)initType).getReturnType(context); + if (initReturnType != null) { + match(initReturnType, qualifierType, context, substitutions); + } + } } } } diff --git a/python/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/src/com/jetbrains/python/psi/types/PyUnionType.java index abdc5ad34428..8572b72c1771 100644 --- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java @@ -77,13 +77,12 @@ public class PyUnionType implements PyType { } /** - * @param context * @return true if all types in the union are built-in. */ @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { for (PyType one : myMembers) { - if (one == null || !one.isBuiltin(context)) return false; + if (one == null || !one.isBuiltin()) return false; } return true; } diff --git a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java index 719bc833d1bf..6895249a641f 100644 --- a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java +++ b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java @@ -153,7 +153,7 @@ public class PyChangeSignatureHandler implements ChangeSignatureHandler { final PyClass baseClass = deepestSuperMethod.getContainingClass(); final PyBuiltinCache cache = PyBuiltinCache.getInstance(baseClass); String baseClassName = baseClass == null? "" : baseClass.getName(); - if (cache.hasInBuiltins(baseClass)) + if (cache.isBuiltin(baseClass)) return function; final String message = PyBundle.message( "refactoring.change.signature.find.usages.of.base.class", diff --git a/python/src/com/jetbrains/python/refactoring/classes/DependencyVisitor.java b/python/src/com/jetbrains/python/refactoring/classes/DependencyVisitor.java index b22449d9abb0..6cb4504bb960 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/DependencyVisitor.java +++ b/python/src/com/jetbrains/python/refactoring/classes/DependencyVisitor.java @@ -38,9 +38,24 @@ class DependencyVisitor extends PyRecursiveElementVisitor { } final String calleeName = callee.getName(); - if ((calleeName != null) && calleeName.equals(myElementToFind.getName())) { // Check by name also + final String name = myElementToFind.getName(); + if ((calleeName != null) && calleeName.equals(name)) { // Check by name also myDependencyFound = true; } + + // Member could be used as method param + final PyArgumentList list = node.getArgumentList(); + if (list != null) { + for (final PyExpression expression : node.getArgumentList().getArgumentExpressions()) { + final PsiReference reference = expression.getReference(); + if ((reference != null) && reference.isReferenceTo(myElementToFind)) { + myDependencyFound = true; + } + if ((name != null) && name.equals(expression.getName())) { + myDependencyFound = true; + } + } + } } } diff --git a/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java b/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java index 79f0382a8e23..25b8a23703cf 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java +++ b/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java @@ -125,7 +125,7 @@ public final class PyClassRefactoringUtil { } @NotNull - public static List<PyFunction> copyMethods(Collection<PyFunction> methods, PyClass superClass) { + public static List<PyFunction> copyMethods(Collection<PyFunction> methods, PyClass superClass, boolean skipIfExist ) { if (methods.isEmpty()) { return Collections.emptyList(); } @@ -133,7 +133,7 @@ public final class PyClassRefactoringUtil { rememberNamedReferences(e); } final PyFunction[] elements = methods.toArray(new PyFunction[methods.size()]); - return addMethods(superClass, true, elements); + return addMethods(superClass, skipIfExist, elements); } /** @@ -298,7 +298,7 @@ public final class PyClassRefactoringUtil { } public static boolean insertImport(PsiElement anchor, PsiNamedElement element, @Nullable String asName, boolean preferFromImport) { - if (PyBuiltinCache.getInstance(element).hasInBuiltins(element)) return false; + if (PyBuiltinCache.getInstance(element).isBuiltin(element)) return false; final PsiFile newFile = element.getContainingFile(); final PsiFile file = anchor.getContainingFile(); if (newFile == file) return false; diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/ClassFieldsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/ClassFieldsManager.java index 3bf4f00553e1..281ad586bdd7 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/ClassFieldsManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/ClassFieldsManager.java @@ -1,9 +1,9 @@ package com.jetbrains.python.refactoring.classes.membersManager; -import com.jetbrains.python.psi.PyAssignmentStatement; -import com.jetbrains.python.psi.PyClass; -import com.jetbrains.python.psi.PyElement; -import com.jetbrains.python.psi.PyTargetExpression; +import com.google.common.collect.FluentIterable; +import com.jetbrains.NotNullPredicate; +import com.jetbrains.python.PyNames; +import com.jetbrains.python.psi.*; import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil; import org.jetbrains.annotations.NotNull; @@ -31,8 +31,21 @@ class ClassFieldsManager extends FieldsManager { protected Collection<PyElement> moveAssignments(@NotNull final PyClass from, @NotNull final Collection<PyAssignmentStatement> statements, @NotNull final PyClass... to) { + return moveAssignmentsImpl(from, statements, to); + } + + /** + * Moves assignments from one class to anothers + * @param from source + * @param statements assignments + * @param to destination + * @return newly created assignments + */ + static Collection<PyElement> moveAssignmentsImpl(@NotNull final PyClass from, + @NotNull final Collection<PyAssignmentStatement> statements, + @NotNull final PyClass... to) { //TODO: Copy/paste with InstanceFieldsManager. Move to parent? - final List<PyElement> result = new ArrayList<PyElement>(); + final Collection<PyElement> result = new ArrayList<PyElement>(); for (final PyClass destClass : to) { result.addAll(PyClassRefactoringUtil.copyFieldDeclarationToStatement(statements, destClass.getStatementList(), destClass)); } @@ -49,6 +62,39 @@ class ClassFieldsManager extends FieldsManager { @NotNull @Override protected List<PyTargetExpression> getFieldsByClass(@NotNull final PyClass pyClass) { - return pyClass.getClassAttributes(); + return FluentIterable.from(pyClass.getClassAttributes()).filter(new NoMetaAndProperties(pyClass)).toList(); + } + + /** + * Exclude "__metaclass__" field and properties (there should be separate managers for them) + * TODO: Check type and filter out any builtin element instead? + */ + private static class NoMetaAndProperties extends NotNullPredicate<PyTargetExpression> { + @NotNull + private final PyClass myClass; + + private NoMetaAndProperties(@NotNull final PyClass aClass) { + myClass = aClass; + } + + @Override + public boolean applyNotNull(@NotNull final PyTargetExpression input) { + final String name = input.getName(); + if (name == null) { + return false; + } + if (name.equals(PyNames.DUNDER_METACLASS)) { + return false; + } + + final PyExpression assignedValue = input.findAssignedValue(); + if (assignedValue instanceof PyCallExpression) { + final PyExpression callee = ((PyCallExpression)assignedValue).getCallee(); + if ((callee != null) && PyNames.PROPERTY.equals(callee.getName()) && (myClass.findProperty(name, false) != null)) { + return false; + } + } + return true; + } } } diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/FieldsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/FieldsManager.java index cb15b2b561a4..5dd32888ec22 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/FieldsManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/FieldsManager.java @@ -43,9 +43,9 @@ abstract class FieldsManager extends MembersManager<PyTargetExpression> { @NotNull @Override protected MultiMap<PyClass, PyElement> getDependencies(@NotNull final PyElement member) { - final MultiMap<PyClass, PyElement> result = new MultiMap<PyClass, PyElement>(); - member.accept(new MyPyRecursiveElementVisitor(result)); - return result; + final PyRecursiveElementVisitorWithResult visitor = new MyPyRecursiveElementVisitor(); + member.accept(visitor); + return visitor.myResult; } @Override @@ -89,7 +89,7 @@ abstract class FieldsManager extends MembersManager<PyTargetExpression> { * @return list of fields in target expression (declaration) form */ @NotNull - protected abstract List<PyTargetExpression> getFieldsByClass(@NotNull PyClass pyClass); + protected abstract Collection<PyTargetExpression> getFieldsByClass(@NotNull PyClass pyClass); @NotNull @@ -135,13 +135,7 @@ abstract class FieldsManager extends MembersManager<PyTargetExpression> { /** * Fetches field declarations */ - private static class MyPyRecursiveElementVisitor extends PyRecursiveElementVisitor { - @NotNull - private final MultiMap<PyClass, PyElement> myResult; - - private MyPyRecursiveElementVisitor(@NotNull final MultiMap<PyClass, PyElement> result) { - myResult = result; - } + private static class MyPyRecursiveElementVisitor extends PyRecursiveElementVisitorWithResult { @Override public void visitPyReferenceExpression(final PyReferenceExpression node) { diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java index a1e19c455a0f..357d9e896c00 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java @@ -8,7 +8,6 @@ import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyFunctionBuilder; import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -18,6 +17,7 @@ import java.util.List; * @author Ilya.Kazakevich */ class InstanceFieldsManager extends FieldsManager { + private static final FieldsOnly FIELDS_ONLY = new FieldsOnly(); // PY-12170 @@ -92,8 +92,8 @@ class InstanceFieldsManager extends FieldsManager { @NotNull @Override - protected List<PyTargetExpression> getFieldsByClass(@NotNull final PyClass pyClass) { - return pyClass.getInstanceAttributes(); + protected Collection<PyTargetExpression> getFieldsByClass(@NotNull final PyClass pyClass) { + return Collections2.filter(pyClass.getInstanceAttributes(), FIELDS_ONLY); } private static class InitsOnly extends NotNullPredicate<PyAssignmentStatement> { @@ -115,4 +115,11 @@ class InstanceFieldsManager extends FieldsManager { return myInitMethod.equals(functionWhereDeclared); } } + + private static class FieldsOnly extends NotNullPredicate<PyTargetExpression> { + @Override + protected boolean applyNotNull(@NotNull final PyTargetExpression input) { + return input.getReference().resolve() instanceof PyTargetExpression; + } + } } diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersManager.java index 437b8085d765..b2d8dac2c4a8 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersManager.java @@ -20,7 +20,6 @@ import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiNamedElement; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.MultiMap; import com.jetbrains.NotNullPredicate; @@ -45,7 +44,11 @@ public abstract class MembersManager<T extends PyElement> implements Function<T, * List of managers. Class delegates all logic to them. */ private static final Collection<? extends MembersManager<? extends PyElement>> MANAGERS = - Arrays.asList(new MethodsManager(), new SuperClassesManager(), new ClassFieldsManager(), new InstanceFieldsManager()); + Arrays.asList(new MethodsManager(), + new SuperClassesManager(), + new ClassFieldsManager(), + new InstanceFieldsManager(), + new PropertiesManager()); @NotNull private final Class<T> myExpectedClass; @@ -84,7 +87,7 @@ public abstract class MembersManager<T extends PyElement> implements Function<T, @SuppressWarnings({"unchecked", "rawtypes"}) //We check type at runtime private static Collection<PyMemberInfo<PyElement>> transformSafely(@NotNull final PyClass pyClass, @NotNull final MembersManager<?> manager) { - final List<PyElement> membersCouldBeMoved = manager.getMembersCouldBeMoved(pyClass); + final List<? extends PyElement> membersCouldBeMoved = manager.getMembersCouldBeMoved(pyClass); manager.checkElementTypes((Iterable)membersCouldBeMoved); return (Collection<PyMemberInfo<PyElement>>)Collections2.transform(membersCouldBeMoved, (Function)manager); } @@ -175,7 +178,8 @@ public abstract class MembersManager<T extends PyElement> implements Function<T, /** * Finds member in class. - * @param pyClass class to find member in + * + * @param pyClass class to find member in * @param pyElement element to find * @return member info with element */ @@ -195,25 +199,10 @@ public abstract class MembersManager<T extends PyElement> implements Function<T, * @return list of members */ @NotNull - protected abstract List<PyElement> getMembersCouldBeMoved(@NotNull PyClass pyClass); + protected abstract List<? extends PyElement> getMembersCouldBeMoved(@NotNull PyClass pyClass); /** - * Filters out named elements (ones that subclasses {@link com.intellij.psi.PsiNamedElement}) and {@link com.jetbrains.python.psi.PyElement}) - * that are null or has null name. - * You need it sometimes when code has errors (i.e. bad formatted code with annotation may treat annotation as method with null name. - * note: we should probably throw exceptions in such cases and display "refactoring not available" window in handler) - * - * @param elementsToFilter collection of elements to filter - * @param <T> element type - * @return collection of T with out of nulls and elemens whos {@link com.intellij.psi.PsiNamedElement#getName()} returns null - */ - @NotNull - protected static <T extends PsiNamedElement & PyElement> Collection<T> filterNameless(@NotNull final Collection<T> elementsToFilter) { - return Collections2.filter(elementsToFilter, new NamelessFilter<T>()); - } - - /** * Returns list of elements that may require reference storing aid from {@link com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil#rememberNamedReferences(com.intellij.psi.PsiElement, String...)} * * @param elements members chosen by user. In most cases members their selves could be stored, but different managers may support other strategies @@ -227,6 +216,7 @@ public abstract class MembersManager<T extends PyElement> implements Function<T, /** * Moves element from one class to another. Returns members that may require reference restoring aid from * ({@link com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil#restoreNamedReferences(com.intellij.psi.PsiElement)}) + * Sort members according to their dependncies, before calling this method * * @see #getElementsToStoreReferences(java.util.Collection) */ @@ -357,13 +347,6 @@ public abstract class MembersManager<T extends PyElement> implements Function<T, } } - private static class NamelessFilter<T extends PyElement & PsiNamedElement> extends NotNullPredicate<T> { - @Override - public boolean applyNotNull(@NotNull final T input) { - return input.getName() != null; - } - } - private static class FindByElement extends NotNullPredicate<PyMemberInfo<PyElement>> { private final PyElement myPyElement; diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java index 7cba0a2a639c..52c32d95d38d 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java @@ -1,7 +1,8 @@ package com.jetbrains.python.refactoring.classes.membersManager; +import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import com.google.common.collect.Lists; +import com.google.common.collect.FluentIterable; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -35,6 +36,7 @@ class MethodsManager extends MembersManager<PyFunction> { {PyNames.PROPERTY, PyNames.CLASSMETHOD, PyNames.STATICMETHOD}; public static final String ABC_META_PACKAGE = "abc"; + private static final NoPropertiesPredicate NO_PROPERTIES = new NoPropertiesPredicate(); MethodsManager() { super(PyFunction.class); @@ -54,16 +56,15 @@ class MethodsManager extends MembersManager<PyFunction> { @NotNull @Override protected MultiMap<PyClass, PyElement> getDependencies(@NotNull final PyElement member) { - final MultiMap<PyClass, PyElement> result = new MultiMap<PyClass, PyElement>(); - member.accept(new MyPyRecursiveElementVisitor(result)); - - return result; + final MyPyRecursiveElementVisitor visitor = new MyPyRecursiveElementVisitor(); + member.accept(visitor); + return visitor.myResult; } @NotNull @Override - protected List<PyElement> getMembersCouldBeMoved(@NotNull final PyClass pyClass) { - return Lists.<PyElement>newArrayList(filterNameless(Arrays.asList(pyClass.getMethods()))); + protected List<? extends PyElement> getMembersCouldBeMoved(@NotNull final PyClass pyClass) { + return FluentIterable.from(Arrays.asList(pyClass.getMethods())).filter(new NamelessFilter<PyFunction>()).filter(NO_PROPERTIES).toList(); } @Override @@ -74,7 +75,7 @@ class MethodsManager extends MembersManager<PyFunction> { final Collection<PyFunction> methodsToAbstract = fetchElements(Collections2.filter(members, new AbstractFilter(true))); makeMethodsAbstract(methodsToAbstract, to); - return moveMethods(from, methodsToMove, to); + return moveMethods(from, methodsToMove, true, to); } /** @@ -156,9 +157,10 @@ class MethodsManager extends MembersManager<PyFunction> { * @param from source * @param methodsToMove what to move * @param to where + * @param skipIfExist skip (do not add) if method already exists * @return newly added methods */ - private static List<PyElement> moveMethods(final PyClass from, final Collection<PyFunction> methodsToMove, final PyClass... to) { + static List<PyElement> moveMethods(final PyClass from, final Collection<PyFunction> methodsToMove, final boolean skipIfExist, final PyClass... to) { final List<PyElement> result = new ArrayList<PyElement>(); for (final PyClass destClass : to) { //We move copies here because there may be several destinations @@ -168,7 +170,7 @@ class MethodsManager extends MembersManager<PyFunction> { copies.add(newMethod); } - result.addAll(PyClassRefactoringUtil.copyMethods(copies, destClass)); + result.addAll(PyClassRefactoringUtil.copyMethods(copies, destClass, skipIfExist)); } deleteElements(methodsToMove); @@ -251,14 +253,7 @@ class MethodsManager extends MembersManager<PyFunction> { } } - private static class MyPyRecursiveElementVisitor extends PyRecursiveElementVisitor { - @NotNull - private final MultiMap<PyClass, PyElement> myResult; - - private MyPyRecursiveElementVisitor(@NotNull final MultiMap<PyClass, PyElement> result) { - myResult = result; - } - + private static class MyPyRecursiveElementVisitor extends PyRecursiveElementVisitorWithResult { @Override public void visitPyCallExpression(final PyCallExpression node) { // TODO: refactor, messy code @@ -281,4 +276,14 @@ class MethodsManager extends MembersManager<PyFunction> { } } } + + /** + * Filter out property setters and getters + */ + private static class NoPropertiesPredicate implements Predicate<PyFunction> { + @Override + public boolean apply(@NotNull PyFunction input) { + return input.getProperty() == null; + } + } } diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/NamelessFilter.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/NamelessFilter.java new file mode 100644 index 000000000000..ec688e3f4a9c --- /dev/null +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/NamelessFilter.java @@ -0,0 +1,21 @@ +package com.jetbrains.python.refactoring.classes.membersManager; + +import com.intellij.psi.PsiNamedElement; +import com.jetbrains.NotNullPredicate; +import com.jetbrains.python.psi.PyElement; +import org.jetbrains.annotations.NotNull; + +/** + * Filters out named elements (ones that subclasses {@link com.intellij.psi.PsiNamedElement}) and {@link com.jetbrains.python.psi.PyElement}) + * that are null or has null name. + * You need it sometimes when code has errors (i.e. bad formatted code with annotation may treat annotation as method with null name. + * +* @author Ilya.Kazakevich +*/ +class NamelessFilter<T extends PyElement & PsiNamedElement> extends NotNullPredicate<T> { + + @Override + public boolean applyNotNull(@NotNull final T input) { + return input.getName() != null; + } +} diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/PropertiesManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PropertiesManager.java new file mode 100644 index 000000000000..142bb31e96d9 --- /dev/null +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PropertiesManager.java @@ -0,0 +1,210 @@ +package com.jetbrains.python.refactoring.classes.membersManager; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.MultiMap; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Plugin that moves class properties. + * It represents property (whatever old or new) as one of its methods. + * + * @author Ilya.Kazakevich + */ +class PropertiesManager extends MembersManager<PyElement> { + + PropertiesManager() { + super(PyElement.class); + } + + + @NotNull + @Override + protected List<? extends PyElement> getMembersCouldBeMoved(@NotNull final PyClass pyClass) { + final List<PyElement> elements = new ArrayList<PyElement>(pyClass.getProperties().size()); + for (final Property property : pyClass.getProperties().values()) { + elements.add(getElement(property)); + } + return elements; + } + + @NotNull + private static PyElement getElement(@NotNull final Property property) { + final Callable getter = property.getGetter().valueOrNull(); + final Callable setter = property.getSetter().valueOrNull(); + final Callable deleter = property.getDeleter().valueOrNull(); + + if (getter != null) { + return getter; + } + else if (setter != null) { + return setter; + } + else if (deleter != null) { + return deleter; + } + else { + final PyTargetExpression site = property.getDefinitionSite(); + assert site != null : "Property has no methods nor declaration. That is not property"; + return site; + } + } + + @NotNull + private static Property getProperty(@NotNull final PyClass pyClass, @NotNull final PyElement element) { + final Collection<Property> properties = pyClass.getProperties().values(); + if (element instanceof PyTargetExpression) { + return getPropertyByTargetExpression(properties, (PyTargetExpression)element); + } + if (element instanceof PyFunction) { + return getPropertyByFunction(properties, (PyFunction)element); + } + throw new IllegalArgumentException("Not function nor target"); + } + + @NotNull + private static Property getPropertyByFunction(@NotNull final Collection<Property> properties, + @NotNull final PyFunction functionToSearch) { + for (final Property property : properties) { + for (final PyFunction function : getAllFunctions(property)) { + if (function.equals(functionToSearch)) { + return property; + } + } + } + throw new IllegalArgumentException("No property found"); + } + + @NotNull + private static Property getPropertyByTargetExpression(@NotNull final Iterable<Property> properties, + @NotNull final PyTargetExpression element) { + for (final Property property : properties) { + if (element.equals(property.getDefinitionSite())) { + return property; + } + } + throw new IllegalArgumentException("No property found"); + } + + @NotNull + private static Collection<PyFunction> getAllFunctions(@NotNull final Property property) { + final Collection<PyFunction> result = new ArrayList<PyFunction>(3); + final Callable getter = property.getGetter().valueOrNull(); + final Callable setter = property.getSetter().valueOrNull(); + final Callable deleter = property.getDeleter().valueOrNull(); + + if (getter instanceof PyFunction) { + result.add((PyFunction)getter); + } + if (setter instanceof PyFunction) { + result.add((PyFunction)setter); + } + if (deleter instanceof PyFunction) { + result.add((PyFunction)deleter); + } + return result; + } + + @Override + protected Collection<PyElement> moveMembers(@NotNull final PyClass from, + @NotNull final Collection<PyMemberInfo<PyElement>> members, + @NotNull final PyClass... to) { + final Collection<PyElement> result = new ArrayList<PyElement>(); + + final Collection<PyElement> elements = fetchElements(members); + for (final PyElement element : elements) { + final Property property = getProperty(from, element); + final Collection<PyFunction> functions = getAllFunctions(property); + MethodsManager.moveMethods(from, functions, false, to); + final PyTargetExpression definitionSite = property.getDefinitionSite(); + if (definitionSite != null) { + final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(definitionSite, PyAssignmentStatement.class); + ClassFieldsManager.moveAssignmentsImpl(from, Collections.singleton(assignmentStatement), to); + } + } + return result; + } + + @NotNull + @Override + public PyMemberInfo<PyElement> apply(@NotNull final PyElement input) { + return new PyMemberInfo<PyElement>(input, false, getName(input), false, this, false); + } + + private static String getName(@NotNull final PyElement input) { + final PyClass clazz = PsiTreeUtil.getParentOfType(input, PyClass.class); + assert clazz != null : "Element not declared in class"; + final Property property = getProperty(clazz, input); + return property.getName(); + } + + @Override + public boolean hasConflict(@NotNull final PyElement member, @NotNull final PyClass aClass) { + return false; + } + + @NotNull + @Override + protected MultiMap<PyClass, PyElement> getDependencies(@NotNull final PyElement member) { + final PyRecursiveElementVisitorWithResult visitor = new PyReferenceVisitor(); + member.accept(visitor); + + return visitor.myResult; + } + + @NotNull + @Override + protected Collection<PyElement> getDependencies(@NotNull final MultiMap<PyClass, PyElement> usedElements) { + return Collections.emptyList(); + } + + private static class PyReferenceVisitor extends PyRecursiveElementVisitorWithResult { + + + @Override + public void visitPyExpression(final PyExpression node) { + final PsiReference reference = node.getReference(); + if (reference == null) { + return; + } + + final PsiElement declaration = reference.resolve(); + if (!(declaration instanceof PyFunction)) { + return; + } + + final PyFunction function = (PyFunction)declaration; + final Property property = function.getProperty(); + if (property == null) { + return; + } + + final PyClass aClass = function.getContainingClass(); + if (aClass == null) { + return; + } + final Collection<PyFunction> functions = getAllFunctions(property); + for (final PyFunction pyFunction : functions) { + final PyClass functionClass = pyFunction.getContainingClass(); + if (functionClass != null) { + myResult.putValue(functionClass, pyFunction); + } + } + + final PyTargetExpression definitionSite = property.getDefinitionSite(); + if (definitionSite != null) { + final PyClass pyClass = PsiTreeUtil.getParentOfType(definitionSite, PyClass.class); + if (pyClass != null) { + myResult.putValue(pyClass, definitionSite); + } + } + } + } +} diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyRecursiveElementVisitorWithResult.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyRecursiveElementVisitorWithResult.java new file mode 100644 index 000000000000..14ba3aee84b2 --- /dev/null +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyRecursiveElementVisitorWithResult.java @@ -0,0 +1,19 @@ +package com.jetbrains.python.refactoring.classes.membersManager; + +import com.intellij.util.containers.MultiMap; +import com.jetbrains.python.psi.PyClass; +import com.jetbrains.python.psi.PyElement; +import com.jetbrains.python.psi.PyRecursiveElementVisitor; +import org.jetbrains.annotations.NotNull; + +/** + * Recursive visitor with multimap, to be used for {@link com.jetbrains.python.refactoring.classes.membersManager.MembersManager#getDependencies(com.jetbrains.python.psi.PyElement)} + */ +class PyRecursiveElementVisitorWithResult extends PyRecursiveElementVisitor { + @NotNull + protected final MultiMap<PyClass, PyElement> myResult; + + PyRecursiveElementVisitorWithResult() { + myResult = new MultiMap<PyClass, PyElement>(); + } +} diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java index 7f774010aa8f..f479d104765e 100644 --- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java +++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java @@ -207,7 +207,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler { if (type != null && type != PyNoneType.INSTANCE) { String typeName = type.getName(); if (typeName != null) { - if (type.isBuiltin(context)) { + if (type.isBuiltin()) { typeName = typeName.substring(0, 1); } candidates.addAll(NameSuggesterUtil.generateNamesByType(typeName)); diff --git a/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalDataBase.java b/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalDataBase.java index deb8030f93c7..66cceb192a04 100644 --- a/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalDataBase.java +++ b/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalDataBase.java @@ -15,10 +15,10 @@ */ package com.jetbrains.python.remote; -import com.intellij.remotesdk2.RemoteSdkAdditionalData2; +import com.intellij.remote.RemoteSdkAdditionalData; /** * @author traff */ -public interface PyRemoteSdkAdditionalDataBase extends RemoteSdkAdditionalData2<PyRemoteSdkCredentials>, PySkeletonsPathAware { +public interface PyRemoteSdkAdditionalDataBase extends RemoteSdkAdditionalData<PyRemoteSdkCredentials>, PySkeletonsPathAware { } diff --git a/python/src/com/jetbrains/python/remote/PyRemoteSdkCredentials.java b/python/src/com/jetbrains/python/remote/PyRemoteSdkCredentials.java index 5b5fc9b9e7e3..d9a9f04ecce2 100644 --- a/python/src/com/jetbrains/python/remote/PyRemoteSdkCredentials.java +++ b/python/src/com/jetbrains/python/remote/PyRemoteSdkCredentials.java @@ -15,7 +15,7 @@ */ package com.jetbrains.python.remote; -import com.intellij.remotesdk.RemoteSdkCredentials; +import com.intellij.remote.RemoteSdkCredentials; /** * @author yole diff --git a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java index 40e34f174acc..4276ed8cafe5 100644 --- a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java +++ b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java @@ -27,9 +27,8 @@ import com.intellij.openapi.projectRoots.SdkAdditionalData; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.remotesdk.RemoteInterpreterException; -import com.intellij.remotesdk.RemoteSdkCredentials; -import com.intellij.remotesdk.RemoteSshProcess; +import com.intellij.remote.*; +import com.intellij.remote.RemoteSdkException; import com.intellij.util.NullableConsumer; import com.intellij.util.PathMappingSettings; import com.jetbrains.python.PythonHelpersLocator; @@ -49,21 +48,21 @@ public abstract class PythonRemoteInterpreterManager { public final static ExtensionPointName<PythonRemoteInterpreterManager> EP_NAME = ExtensionPointName.create("Pythonid.remoteInterpreterManager"); public static final String WEB_DEPLOYMENT_PLUGIN_IS_DISABLED = - "Remote interpreter can't be executed. Please enable the Remote Hosts Access plugin."; + "Remote interpreter can't be executed. Please enable the Remote Hosts Access plugin."; //TODO: this message is incorrect public abstract ProcessHandler startRemoteProcess(@Nullable Project project, @NotNull PyRemoteSdkCredentials data, @NotNull GeneralCommandLine commandLine, @Nullable PathMappingSettings mappingSettings) - throws RemoteInterpreterException; + throws RemoteSdkException; public abstract ProcessHandler startRemoteProcessWithPid(@Nullable Project project, @NotNull PyRemoteSdkCredentials data, @NotNull GeneralCommandLine commandLine, @Nullable PathMappingSettings mappingSettings) - throws RemoteInterpreterException; + throws RemoteSdkException; public abstract void addRemoteSdk(Project project, Component parentComponent, Collection<Sdk> existingSdks, NullableConsumer<Sdk> sdkCallback); @@ -74,13 +73,13 @@ public abstract class PythonRemoteInterpreterManager { String[] command, @Nullable String workingDir, boolean askForSudo) - throws RemoteInterpreterException; + throws RemoteSdkException; @NotNull public abstract RemoteSshProcess createRemoteProcess(@Nullable Project project, @NotNull RemoteSdkCredentials data, @NotNull GeneralCommandLine commandLine, boolean allocatePty) - throws RemoteInterpreterException; + throws RemoteSdkException; public abstract boolean editSdk(@NotNull Project project, @NotNull SdkModificator sdkModificator, Collection<Sdk> existingSdks); @@ -140,6 +139,8 @@ public abstract class PythonRemoteInterpreterManager { public abstract SdkAdditionalData loadRemoteSdkData(Sdk sdk, Element additional); + public abstract boolean testConnection(RemoteCredentials credentials); + public static class PyRemoteInterpreterExecutionException extends ExecutionException { public PyRemoteInterpreterExecutionException() { @@ -153,5 +154,11 @@ public abstract class PythonRemoteInterpreterManager { super(WEB_DEPLOYMENT_PLUGIN_IS_DISABLED); } } + + public abstract RemoteCredentials getVagrantRemoteCredentials(VagrantBasedCredentialsHolder data); + + public abstract void checkVagrantStatus(VagrantBasedCredentialsHolder data); + + public abstract RemoteCredentials getCredentialsBySftpServerId(String id); } diff --git a/python/src/com/jetbrains/python/remote/RemoteDebuggableProcessHandler.java b/python/src/com/jetbrains/python/remote/RemoteDebuggableProcessHandler.java index 514fc2a59d8e..db2b329e1fd7 100644 --- a/python/src/com/jetbrains/python/remote/RemoteDebuggableProcessHandler.java +++ b/python/src/com/jetbrains/python/remote/RemoteDebuggableProcessHandler.java @@ -15,7 +15,7 @@ */ package com.jetbrains.python.remote; -import com.intellij.remotesdk.RemoteProcessHandlerBase; +import com.intellij.remote.RemoteProcessHandlerBase; import com.jetbrains.python.debugger.PyDebugProcess; import com.jetbrains.python.debugger.PyPositionConverter; diff --git a/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java b/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java index 5941d5f345c9..673b87dfd53d 100644 --- a/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java +++ b/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java @@ -24,10 +24,8 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkAdditionalData; -import com.intellij.remotesdk2.RemoteSdkAdditionalData2; import com.intellij.util.PathMappingSettings; import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase; -import com.jetbrains.python.remote.PyRemoteSdkCredentials; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.form b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.form deleted file mode 100644 index ea6172e1faac..000000000000 --- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.form +++ /dev/null @@ -1,81 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.sdk.CreateVirtualEnvDialog"> - <grid id="cbd77" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> - <margin top="0" left="0" bottom="0" right="0"/> - <constraints> - <xy x="48" y="54" width="550" height="342"/> - </constraints> - <properties/> - <border type="none"/> - <children> - <component id="23a50" class="javax.swing.JComboBox" binding="mySdkCombo"> - <constraints> - <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties/> - </component> - <vspacer id="b277d"> - <constraints> - <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> - </constraints> - </vspacer> - <component id="48fd" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="&Base interpreter:"/> - </properties> - </component> - <component id="a1259" class="javax.swing.JTextField" binding="myName"> - <constraints> - <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> - <preferred-size width="150" height="-1"/> - </grid> - </constraints> - <properties/> - </component> - <component id="29c55" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <labelFor value="a1259"/> - <text value="&Name:"/> - </properties> - </component> - <component id="1b80c" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myDestination"> - <constraints> - <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties/> - </component> - <component id="42f44" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="&Location:"/> - </properties> - </component> - <component id="41e08" class="com.intellij.ui.components.JBCheckBox" binding="myMakeAvailableToAllProjectsCheckbox"> - <constraints> - <grid row="4" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <selected value="false"/> - <text value="Make available to &all projects"/> - </properties> - </component> - <component id="d10a9" class="com.intellij.ui.components.JBCheckBox" binding="mySitePackagesCheckBox"> - <constraints> - <grid row="3" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <selected value="false"/> - <text value="&Inherit global site-packages"/> - </properties> - </component> - </children> - </grid> -</form> diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java index 104386625e07..e2cfe9c36914 100644 --- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java +++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java @@ -29,16 +29,21 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; +import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.FixedSizeButton; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.platform.LocationNameFieldsBinding; -import com.intellij.remotesdk.RemoteSdkCredentialsHolder; +import com.intellij.remote.RemoteSdkCredentialsHolder; import com.intellij.ui.CollectionComboBoxModel; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.components.JBCheckBox; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.NullableConsumer; import com.intellij.util.PathUtil; import com.intellij.util.PlatformUtils; import com.jetbrains.python.packaging.PyExternalProcessException; @@ -91,7 +96,7 @@ public class CreateVirtualEnvDialog extends IdeaDialog { final String name = SdkConfigurationUtil.createUniqueSdkName(PythonSdkType.getInstance(), sdkHome.getPath(), allSdks); final ProjectJdkImpl sdk = new ProjectJdkImpl(name, PythonSdkType.getInstance()); - sdk.setHomePath(sdkHome.getPath()); + sdk.setHomePath(FileUtil.toSystemDependentName(sdkHome.getPath())); callback.virtualEnvCreated(sdk, associateWithProject); PythonSdkType.setupSdkPaths(sdk, myProject, null); } @@ -111,17 +116,19 @@ public class CreateVirtualEnvDialog extends IdeaDialog { setupDialog(null, allSdks, suggestedBaseSdk); } - private void setupDialog(Project project, List<Sdk> allSdks, @Nullable Sdk suggestedBaseSdk) { + private void setupDialog(Project project, final List<Sdk> allSdks, @Nullable Sdk suggestedBaseSdk) { myProject = project; + layoutPanel(allSdks); + init(); setTitle("Create Virtual Environment"); + Iterables.removeIf(allSdks, new Predicate<Sdk>() { + @Override + public boolean apply(Sdk s) { + return PythonSdkType.isInvalid(s) || PythonSdkType.isVirtualEnv(s) || RemoteSdkCredentialsHolder.isRemoteSdk(s.getHomePath()); + } + }); if (suggestedBaseSdk == null && allSdks.size() > 0) { - Iterables.removeIf(allSdks, new Predicate<Sdk>() { - @Override - public boolean apply(Sdk s) { - return PythonSdkType.isInvalid(s) || PythonSdkType.isVirtualEnv(s) || RemoteSdkCredentialsHolder.isRemoteSdk(s.getHomePath()); - } - }); List<Sdk> sortedSdks = new ArrayList<Sdk>(allSdks); Collections.sort(sortedSdks, new PreferredSdkComparator()); suggestedBaseSdk = sortedSdks.get(0); @@ -139,16 +146,19 @@ public class CreateVirtualEnvDialog extends IdeaDialog { final VirtualFile file = VirtualEnvSdkFlavor.getDefaultLocation(); - if (file != null) + if (file != null) { myInitialPath = file.getPath(); + } else { final String savedPath = PyPackageService.getInstance().getVirtualEnvBasePath(); - if (!StringUtil.isEmptyOrSpaces(savedPath)) + if (!StringUtil.isEmptyOrSpaces(savedPath)) { myInitialPath = savedPath; + } else if (myProject != null) { final VirtualFile baseDir = myProject.getBaseDir(); - if (baseDir != null) + if (baseDir != null) { myInitialPath = baseDir.getPath(); + } } } @@ -167,6 +177,87 @@ public class CreateVirtualEnvDialog extends IdeaDialog { checkValid(); } + private void layoutPanel(final List<Sdk> allSdks) { + final GridBagLayout layout = new GridBagLayout(); + myMainPanel = new JPanel(layout); + + final GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(2,2,2,2); + + c.gridx = 0; + c.gridy = 0; + c.weightx = 0.0; + myMainPanel.add(new JBLabel("Name:"), c); + + c.gridx = 1; + c.gridy = 0; + c.gridwidth = 2; + c.weightx = 1.0; + myName = new JTextField(); + myMainPanel.add(myName, c); + + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 1; + c.weightx = 0.0; + myMainPanel.add(new JBLabel("Location:"), c); + + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 2; + c.weightx = 1.0; + myDestination = new TextFieldWithBrowseButton(); + myMainPanel.add(myDestination, c); + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + c.weightx = 0.0; + myMainPanel.add(new JBLabel("Base interpreter:"), c); + + c.gridx = 1; + c.gridy = 2; + mySdkCombo = new ComboBox(); + c.insets = new Insets(2,2,2,2); + c.weightx = 1.0; + myMainPanel.add(mySdkCombo, c); + + c.gridx = 2; + c.gridy = 2; + c.insets = new Insets(0,0,2,2); + c.weightx = 0.0; + FixedSizeButton button = new FixedSizeButton(); + button.setPreferredSize(myDestination.getButton().getPreferredSize()); + myMainPanel.add(button, c); + + c.gridx = 0; + c.gridy = 3; + c.gridwidth = 3; + c.insets = new Insets(2,2,2,2); + mySitePackagesCheckBox = new JBCheckBox("Inherit global site-packages"); + myMainPanel.add(mySitePackagesCheckBox, c); + + c.gridx = 0; + c.gridy = 4; + myMakeAvailableToAllProjectsCheckbox = new JBCheckBox("Make available to all projects"); + myMainPanel.add(myMakeAvailableToAllProjectsCheckbox, c); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SdkConfigurationUtil.createSdk(myProject, allSdks.toArray(new Sdk[allSdks.size() - 1]), new NullableConsumer<Sdk>() { + @Override + public void consume(@Nullable Sdk sdk) { + if (sdk == null) return; + if (!allSdks.contains(sdk)) { + allSdks.add(sdk); + } + updateSdkList(allSdks, sdk); + } + }, false, PythonSdkType.getInstance()); + } + }); + } + private void checkValid() { final String projectName = myName.getText(); if (new File(getDestination()).exists()) { diff --git a/python/src/com/jetbrains/python/sdk/PySdkUtil.java b/python/src/com/jetbrains/python/sdk/PySdkUtil.java index 4185da7fd42c..d8a2c2f6d0a3 100644 --- a/python/src/com/jetbrains/python/sdk/PySdkUtil.java +++ b/python/src/com/jetbrains/python/sdk/PySdkUtil.java @@ -25,8 +25,7 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.remotesdk.RemoteCredentials; -import com.intellij.remotesdk2.RemoteSdkAdditionalData2; +import com.intellij.remote.RemoteSdkAdditionalData; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NonNls; @@ -214,7 +213,7 @@ public class PySdkUtil { } public static boolean isRemote(@Nullable Sdk sdk) { - return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteSdkAdditionalData2; + return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteSdkAdditionalData; } public static boolean isElementInSkeletons(@NotNull final PsiElement element) { diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java b/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java index c2680224e28a..c0a4226710ed 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java @@ -35,6 +35,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import static com.intellij.openapi.util.JDOMExternalizer.loadStringsList; + /** * @author traff */ @@ -58,16 +60,11 @@ public class PythonSdkAdditionalData implements SdkAdditionalData { } public Object clone() throws CloneNotSupportedException { - try { - final PythonSdkAdditionalData copy = (PythonSdkAdditionalData)super.clone(); - copy.setAddedPaths(getAddedPaths()); - copy.setExcludedPaths(getExcludedPaths()); - copy.setAssociatedProjectPath(getAssociatedProjectPath()); - return copy; - } - catch (CloneNotSupportedException e) { - return null; - } + final PythonSdkAdditionalData copy = new PythonSdkAdditionalData(myFlavor); + copy.setAddedPaths(getAddedPaths()); + copy.setExcludedPaths(getExcludedPaths()); + copy.setAssociatedProjectPath(getAssociatedProjectPath()); + return copy; } public Set<SimpleProjectRoot> getAddedPaths() { @@ -181,16 +178,6 @@ public class PythonSdkAdditionalData implements SdkAdditionalData { return files; } - protected static List<String> loadStringsList(Element element, String rootName, String attrName) { - final List<String> paths = new LinkedList<String>(); - if (element != null) { - @NotNull final List list = element.getChildren(rootName); - for (Object o : list) { - paths.add(((Element)o).getAttribute(attrName).getValue()); - } - } - return paths; - } public Set<VirtualFile> getAddedPathFiles() { return getPathsAsVirtualFiles(myAddedPaths); diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java index df04801e130c..3e0d4ff7e3bf 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java @@ -40,7 +40,7 @@ import java.util.Collection; import java.util.List; public class PythonSdkDetailsStep extends BaseListPopupStep<String> { - private static DialogWrapper myMore; + private DialogWrapper myMore; private final Project myProject; private final Component myOwnerComponent; private final Sdk[] myExistingSdks; @@ -55,21 +55,20 @@ public class PythonSdkDetailsStep extends BaseListPopupStep<String> { final Sdk[] existingSdks, DialogWrapper moreDialog, JComponent ownerComponent, final Point popupPoint, - final boolean showMore, final NullableConsumer<Sdk> callback) { - myMore = moreDialog; - final ListPopupStep sdkHomesStep = new PythonSdkDetailsStep(project, ownerComponent, existingSdks, showMore, callback); + + final ListPopupStep sdkHomesStep = new PythonSdkDetailsStep(project, moreDialog, ownerComponent, existingSdks, callback); final ListPopup popup = JBPopupFactory.getInstance().createListPopup(sdkHomesStep); popup.showInScreenCoordinates(ownerComponent, popupPoint); } public PythonSdkDetailsStep(Project project, - Component ownerComponent, + DialogWrapper moreDialog, Component ownerComponent, Sdk[] existingSdks, - boolean showMore, NullableConsumer<Sdk> callback) { - super(null, getAvailableOptions(showMore)); + super(null, getAvailableOptions(moreDialog != null)); myProject = project; + myMore = moreDialog; myOwnerComponent = ownerComponent; myExistingSdks = existingSdks; myCallback = callback; @@ -154,7 +153,7 @@ public class PythonSdkDetailsStep extends BaseListPopupStep<String> { final List<PythonSdkFlavor> flavors = PythonSdkFlavor.getApplicableFlavors(false); for (PythonSdkFlavor flavor : flavors) { final Collection<String> strings = flavor.suggestHomePaths(); - for (String string : strings) { + for (String string : SdkConfigurationUtil.filterExistingPaths(PythonSdkType.getInstance(), strings, myExistingSdks)) { allSdks.add(new PyDetectedSdk(string)); } } diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index 6aa0c6d85df1..b13cb762cae4 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -51,8 +51,8 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.reference.SoftReference; -import com.intellij.remotesdk.RemoteSdkCredentials; -import com.intellij.remotesdk.RemoteSdkCredentialsHolder; +import com.intellij.remote.RemoteSdkCredentials; +import com.intellij.remote.RemoteSdkCredentialsHolder; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.NullableConsumer; @@ -282,7 +282,7 @@ public class PythonSdkType extends SdkType { final Point point = parentComponent.getMousePosition(); SwingUtilities.convertPointToScreen(point, parentComponent); PythonSdkDetailsStep - .show(project, sdkModel.getSdks(), null, parentComponent, point, false, new NullableConsumer<Sdk>() { + .show(project, sdkModel.getSdks(), null, parentComponent, point, new NullableConsumer<Sdk>() { @Override public void consume(@Nullable Sdk sdk) { if (sdk != null) { @@ -407,18 +407,19 @@ public class PythonSdkType extends SdkType { } public static String suggestSdkNameFromVersion(String sdkHome, String version) { - final String short_home_name = FileUtil.getLocationRelativeToUserHome(sdkHome); + sdkHome = FileUtil.toSystemDependentName(sdkHome); + final String shortHomeName = FileUtil.getLocationRelativeToUserHome(sdkHome); if (version != null) { - File virtualenv_root = getVirtualEnvRoot(sdkHome); - if (virtualenv_root != null) { - version += " virtualenv at " + FileUtil.getLocationRelativeToUserHome(virtualenv_root.getAbsolutePath()); + File virtualEnvRoot = getVirtualEnvRoot(sdkHome); + if (virtualEnvRoot != null) { + version += " virtualenv at " + FileUtil.getLocationRelativeToUserHome(virtualEnvRoot.getAbsolutePath()); } else { - version += " (" + short_home_name + ")"; + version += " (" + shortHomeName + ")"; } } else { - version = "Unknown at " + short_home_name; + version = "Unknown at " + shortHomeName; } // last resort return version; } @@ -480,10 +481,10 @@ public class PythonSdkType extends SdkType { if (flavor != null) { VirtualFile sdkPath = flavor.getSdkPath(homePath); if (sdkPath != null) { - return sdkPath.getPath(); + return FileUtil.toSystemDependentName(sdkPath.getPath()); } } - return path; + return FileUtil.toSystemDependentName(path); } public void setupSdkPaths(@NotNull final Sdk sdk) { @@ -658,9 +659,9 @@ public class PythonSdkType extends SdkType { } public static void addSdkRoot(SdkModificator sdkModificator, String path) { - VirtualFile child = LocalFileSystem.getInstance().refreshAndFindFileByPath(path); - if (child != null) { - addSdkRoot(sdkModificator, child); + final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path); + if (file != null) { + addSdkRoot(sdkModificator, file); } else { LOG.info("Bogus sys.path entry " + path); @@ -668,19 +669,26 @@ public class PythonSdkType extends SdkType { } private static void addSdkRoot(@NotNull SdkModificator sdkModificator, @NotNull VirtualFile child) { - @NonNls String suffix = child.getExtension(); - if (suffix != null) suffix = suffix.toLowerCase(); // Why on earth empty suffix is null and not ""? - VirtualFile toAdd = child; - if ((!child.isDirectory()) && ("zip".equals(suffix) || "egg".equals(suffix))) { - // a .zip / .egg file must have its root extracted first - toAdd = JarFileSystem.getInstance().getJarRootForLocalFile(child); + // NOTE: Files marked as library sources are not considered part of project source. Since the directory of the project the + // user is working on is included in PYTHONPATH with many configurations (e.g. virtualenv), we must not mark SDK paths as + // library sources, only as classes. + sdkModificator.addRoot(getSdkRootVirtualFile(child), OrderRootType.CLASSES); + } + + @NotNull + public static VirtualFile getSdkRootVirtualFile(@NotNull VirtualFile path) { + String suffix = path.getExtension(); + if (suffix != null) { + suffix = suffix.toLowerCase(); // Why on earth empty suffix is null and not ""? } - if (toAdd != null) { - // NOTE: Files marked as library sources are not considered part of project source. Since the directory of the project the - // user is working on is included in PYTHONPATH with many configurations (e.g. virtualenv), we must not mark SDK paths as - // library sources, only as classes. - sdkModificator.addRoot(toAdd, OrderRootType.CLASSES); + if ((!path.isDirectory()) && ("zip".equals(suffix) || "egg".equals(suffix))) { + // a .zip / .egg file must have its root extracted first + final VirtualFile jar = JarFileSystem.getInstance().getJarRootForLocalFile(path); + if (jar != null) { + return jar; + } } + return path; } public static String getSkeletonsPath(String basePath, String sdkHome) { diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java index 2cc749f72002..a964fa90246e 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java @@ -31,6 +31,7 @@ import com.intellij.openapi.projectRoots.SdkTypeId; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.startup.StartupActivity; import com.intellij.openapi.util.io.FileUtilRt; +import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.python.PyBundle; import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil; @@ -38,7 +39,6 @@ import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.io.IOException; import java.util.*; /** @@ -135,7 +135,7 @@ public class PythonSdkUpdater implements StartupActivity { } } - private static void updateSysPath(final Sdk sdk) throws InvalidSdkException { + private static void updateSysPath(@NotNull final Sdk sdk) throws InvalidSdkException { long start_time = System.currentTimeMillis(); final List<String> sysPath = PythonSdkType.getSysPath(sdk.getHomePath()); final VirtualFile file = PyUserSkeletonsUtil.getUserSkeletonsDirectory(); @@ -151,9 +151,29 @@ public class PythonSdkUpdater implements StartupActivity { LOG.info("Updating sys.path took " + (System.currentTimeMillis() - start_time) + " ms"); } - private static void updateSdkPath(Sdk sdk, List<String> sysPath) { + /** + * Updates SDK based on sys.path and cleans legacy information up. + */ + private static void updateSdkPath(@NotNull Sdk sdk, @NotNull List<String> sysPath) { + final SdkModificator modificator = sdk.getSdkModificator(); + boolean changed = addNewSysPathEntries(sdk, modificator, sysPath); + changed = removeSourceRoots(sdk, modificator) || changed; + changed = removeDuplicateClassRoots(sdk, modificator) || changed; + if (changed) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + modificator.commitChanges(); + } + }); + } + } + + /** + * Adds new CLASSES entries found in sys.path. + */ + private static boolean addNewSysPathEntries(@NotNull Sdk sdk, @NotNull SdkModificator modificator, @NotNull List<String> sysPath) { final List<VirtualFile> oldRoots = Arrays.asList(sdk.getRootProvider().getFiles(OrderRootType.CLASSES)); - final VirtualFile[] sourceRoots = sdk.getRootProvider().getFiles(OrderRootType.SOURCES); PythonSdkAdditionalData additionalData = sdk.getSdkAdditionalData() instanceof PythonSdkAdditionalData ? (PythonSdkAdditionalData)sdk.getSdkAdditionalData() : null; @@ -166,37 +186,49 @@ public class PythonSdkUpdater implements StartupActivity { newRoots.add(root); } } - if (!newRoots.isEmpty() || sourceRoots.length > 0) { - final SdkModificator modificator = sdk.getSdkModificator(); + if (!newRoots.isEmpty()) { for (String root : newRoots) { PythonSdkType.addSdkRoot(modificator, root); } - modificator.removeRoots(OrderRootType.SOURCES); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - modificator.commitChanges(); - } - }); + return true; } + return false; } - private static boolean wasOldRoot(String root, Collection<VirtualFile> virtualFiles) { - String rootPath = canonicalize(root); - for (VirtualFile virtualFile : virtualFiles) { - if (canonicalize(virtualFile.getPath()).equals(rootPath)) { - return true; + /** + * Removes duplicate roots that have been added as the result of a bug with *.egg handling. + */ + private static boolean removeDuplicateClassRoots(@NotNull Sdk sdk, @NotNull SdkModificator modificator) { + final List<VirtualFile> sourceRoots = Arrays.asList(sdk.getRootProvider().getFiles(OrderRootType.CLASSES)); + final LinkedHashSet<VirtualFile> uniqueRoots = new LinkedHashSet<VirtualFile>(sourceRoots); + if (uniqueRoots.size() != sourceRoots.size()) { + modificator.removeRoots(OrderRootType.CLASSES); + for (VirtualFile root : uniqueRoots) { + modificator.addRoot(root, OrderRootType.CLASSES); } + return true; } return false; } - private static String canonicalize(String path) { - try { - return new File(path).getCanonicalPath(); + /** + * Removes legacy SOURCES entries in Python SDK tables (PY-2891). + */ + private static boolean removeSourceRoots(@NotNull Sdk sdk, @NotNull SdkModificator modificator) { + final VirtualFile[] sourceRoots = sdk.getRootProvider().getFiles(OrderRootType.SOURCES); + if (sourceRoots.length > 0) { + modificator.removeRoots(OrderRootType.SOURCES); + return true; } - catch (IOException e) { - return path; + return false; + } + + private static boolean wasOldRoot(@NotNull String root, @NotNull Collection<VirtualFile> oldRoots) { + final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(root); + if (file != null) { + final VirtualFile rootFile = PythonSdkType.getSdkRootVirtualFile(file); + return oldRoots.contains(rootFile); } + return false; } } diff --git a/python/src/com/jetbrains/python/sdk/flavors/MacPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/MacPythonSdkFlavor.java index 5d241b668166..72c8f422f153 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/MacPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/MacPythonSdkFlavor.java @@ -15,14 +15,14 @@ */ package com.jetbrains.python.sdk.flavors; +import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VFileProperty; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.util.containers.HashSet; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.Set; /** * @author yole @@ -36,30 +36,35 @@ public class MacPythonSdkFlavor extends CPythonSdkFlavor { @Override public Collection<String> suggestHomePaths() { - List<String> candidates = new ArrayList<String>(); + Set<String> candidates = new HashSet<String>(); collectPythonInstallations("/Library/Frameworks/Python.framework/Versions", candidates); collectPythonInstallations("/System/Library/Frameworks/Python.framework/Versions", candidates); UnixPythonSdkFlavor.collectUnixPythons("/usr/local/bin", candidates); return candidates; } - private static void collectPythonInstallations(String pythonPath, List<String> candidates) { + private static void collectPythonInstallations(String pythonPath, Set<String> candidates) { VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(pythonPath); if (rootVDir != null) { if (rootVDir instanceof NewVirtualFile) { ((NewVirtualFile)rootVDir).markDirty(); } - rootVDir.refresh(false, false); + rootVDir.refresh(true, false); for (VirtualFile dir : rootVDir.getChildren()) { - final String dir_name = dir.getName().toLowerCase(); + final String dirName = dir.getName().toLowerCase(); if (dir.isDirectory()) { - if ("Current".equals(dir_name) || dir_name.startsWith("2") || dir_name.startsWith("3")) { + if ("Current".equals(dirName) || dirName.startsWith("2") || dirName.startsWith("3")) { final VirtualFile binDir = dir.findChild("bin"); if (binDir != null && binDir.isDirectory()) { for (String name : POSSIBLE_BINARY_NAMES) { final VirtualFile child = binDir.findChild(name); - if (child != null && !child.is(VFileProperty.SYMLINK)) { - candidates.add(child.getPath()); + if (child == null) continue; + String path = child.getPath(); + if (FileSystemUtil.isSymLink(path)) { + path = FileSystemUtil.resolveSymLink(path); + } + if (path != null && !candidates.contains(path)) { + candidates.add(path); break; } } diff --git a/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java index 0ad83294398b..271afc6e8c2f 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java @@ -17,7 +17,7 @@ package com.jetbrains.python.sdk.flavors; import com.google.common.collect.Lists; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.remotesdk.RemoteFile; +import com.intellij.remote.RemoteFile; import org.jetbrains.annotations.Nullable; import java.util.Collection; diff --git a/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java index 2440661877ff..b01424b66c3a 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java @@ -15,14 +15,14 @@ */ package com.jetbrains.python.sdk.flavors; +import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VFileProperty; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.util.containers.HashSet; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.Set; /** * @author yole @@ -37,12 +37,12 @@ public class UnixPythonSdkFlavor extends CPythonSdkFlavor { @Override public Collection<String> suggestHomePaths() { - List<String> candidates = new ArrayList<String>(); + Set<String> candidates = new HashSet<String>(); collectUnixPythons("/usr/bin", candidates); return candidates; } - public static void collectUnixPythons(String path, List<String> candidates) { + public static void collectUnixPythons(String path, Set<String> candidates) { VirtualFile rootDir = LocalFileSystem.getInstance().findFileByPath(path); if (rootDir != null) { if (rootDir instanceof NewVirtualFile) { @@ -55,9 +55,13 @@ public class UnixPythonSdkFlavor extends CPythonSdkFlavor { final String childName = child.getName(); for (String name : NAMES) { if (childName.startsWith(name)) { - if (!childName.endsWith("-config") && !childName.startsWith("pythonw") && - !childName.endsWith("m") && !child.is(VFileProperty.SYMLINK)) { - candidates.add(child.getPath()); + String childPath = child.getPath(); + if (FileSystemUtil.isSymLink(childPath)) { + childPath = FileSystemUtil.resolveSymLink(childPath); + } + if (childPath != null && !childName.endsWith("-config") && !childName.startsWith("pythonw") && !childName.endsWith("m") && + !candidates.contains(childPath)) { + candidates.add(childPath); } break; } diff --git a/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java index b9de2e2c9003..b9bdf8fc11c4 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java @@ -111,7 +111,7 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { for (String name : NAMES) { if (SystemInfo.isWindows) { if (childName.equals(name)) { - return child.getPath(); + return FileUtil.toSystemDependentName(child.getPath()); } } else { diff --git a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java index 9de862f66fac..8e75e634755b 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java @@ -40,7 +40,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor { public Collection<String> suggestHomePaths() { Set<String> candidates = new TreeSet<String>(); findInCandidatePaths(candidates, "python.exe", "jython.bat", "pypy.exe"); - candidates.add(PythonHelpersLocator.getHelpersRoot().getParent()); + findInstallations(candidates, "python.exe", PythonHelpersLocator.getHelpersRoot().getParent()); return candidates; } @@ -66,7 +66,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor { } File f = new File(pathEntry, exeName); if (f.exists()) { - candidates.add(FileUtil.toSystemIndependentName(f.getPath())); + candidates.add(FileUtil.toSystemDependentName(f.getPath())); } } } @@ -81,7 +81,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor { for (VirtualFile dir : rootVDir.getChildren()) { if (dir.isDirectory() && dir.getName().toLowerCase().startsWith(dir_prefix)) { VirtualFile python_exe = dir.findChild(exe_name); - if (python_exe != null) candidates.add(FileUtil.toSystemIndependentName(python_exe.getPath())); + if (python_exe != null) candidates.add(FileUtil.toSystemDependentName(python_exe.getPath())); } } } diff --git a/python/src/com/jetbrains/python/validation/PyAnnotatingVisitor.java b/python/src/com/jetbrains/python/validation/PyAnnotatingVisitor.java index 39ab3639751a..8accd9854acc 100644 --- a/python/src/com/jetbrains/python/validation/PyAnnotatingVisitor.java +++ b/python/src/com/jetbrains/python/validation/PyAnnotatingVisitor.java @@ -31,10 +31,7 @@ import java.util.List; */ public class PyAnnotatingVisitor implements Annotator { private static final Logger LOGGER = Logger.getInstance(PyAnnotatingVisitor.class.getName()); - - private final List<PyAnnotator> myAnnotators = new ArrayList<PyAnnotator>(); - - private final Class[] ANNOTATOR_CLASSES = new Class[] { + private static final Class[] ANNOTATOR_CLASSES = new Class[] { AssignTargetAnnotator.class, ParameterListAnnotator.class, HighlightingAnnotator.class, @@ -44,10 +41,13 @@ public class PyAnnotatingVisitor implements Annotator { GlobalAnnotator.class, ImportAnnotator.class, PyBuiltinAnnotator.class, - UnsupportedFeatures.class + UnsupportedFeatures.class }; + private final PyAnnotator[] myAnnotators; + public PyAnnotatingVisitor() { + final List<PyAnnotator> annotators = new ArrayList<PyAnnotator>(); for (Class cls : ANNOTATOR_CLASSES) { PyAnnotator annotator; try { @@ -61,13 +61,14 @@ public class PyAnnotatingVisitor implements Annotator { LOGGER.error(e); continue; } - myAnnotators.add(annotator); + annotators.add(annotator); } + myAnnotators = annotators.toArray(new PyAnnotator[annotators.size()]); } public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) { final PsiFile file = psiElement.getContainingFile(); - for(PyAnnotator annotator: myAnnotators) { + for (PyAnnotator annotator : myAnnotators) { if (file instanceof PyFileImpl && !((PyFileImpl)file).isAcceptedFor(annotator.getClass())) continue; annotator.annotateElement(psiElement, holder); } diff --git a/python/src/com/jetbrains/python/validation/PyBuiltinAnnotator.java b/python/src/com/jetbrains/python/validation/PyBuiltinAnnotator.java index 417c3621d095..102867fba9a6 100644 --- a/python/src/com/jetbrains/python/validation/PyBuiltinAnnotator.java +++ b/python/src/com/jetbrains/python/validation/PyBuiltinAnnotator.java @@ -18,67 +18,63 @@ package com.jetbrains.python.validation; import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.Annotation; import com.intellij.psi.PsiElement; -import com.intellij.psi.ResolveResult; -import com.jetbrains.python.highlighting.PyHighlighter; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; +import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; +import com.jetbrains.python.highlighting.PyHighlighter; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; +import org.jetbrains.annotations.NotNull; /** * Marks built-in names. - * User: dcheryasov - * Date: Jan 10, 2009 12:17:15 PM + * + * @author dcheryasov */ public class PyBuiltinAnnotator extends PyAnnotator { @Override public void visitPyReferenceExpression(PyReferenceExpression node) { final String name = node.getName(); - if (name == null) return; - boolean highlighted_as_attribute = highlightAsAttribute(node, name); - if (! highlighted_as_attribute && !node.isQualified()) { - // things like len() - ResolveResult[] resolved = node.getReference().multiResolve(false); // constructors, etc may give multiple results... - if (resolved.length > 0) { - if (PyBuiltinCache.getInstance(node).hasInBuiltins(resolved[0].getElement())) { // ...but we only care about the default resolution - Annotation ann; - PsiElement parent = node.getParent(); - if (parent instanceof PyDecorator) { - // don't mark the entire decorator, only mark the "@", else we'll conflict with deco annotator - ann = getHolder().createInfoAnnotation(parent.getFirstChild(), null); // first child is there, or we'd not parse as deco - } - else ann = getHolder().createInfoAnnotation(node, null); - ann.setTextAttributes(PyHighlighter.PY_BUILTIN_NAME); - } + if (name == null) return; + final boolean highlightedAsAttribute = highlightAsAttribute(node, name); + if (!highlightedAsAttribute && PyBuiltinCache.isInBuiltins(node)) { + final Annotation ann; + final PsiElement parent = node.getParent(); + if (parent instanceof PyDecorator) { + // don't mark the entire decorator, only mark the "@", else we'll conflict with deco annotator + ann = getHolder().createInfoAnnotation(parent.getFirstChild(), null); // first child is there, or we'd not parse as deco + } + else { + ann = getHolder().createInfoAnnotation(node, null); } + ann.setTextAttributes(PyHighlighter.PY_BUILTIN_NAME); } } @Override public void visitPyTargetExpression(PyTargetExpression node) { final String name = node.getName(); - if (name == null) return; - highlightAsAttribute(node, name); + if (name != null) { + highlightAsAttribute(node, name); + } } /** * Try to highlight a node as a class attribute. + * * @param node what to work with - * @return true iff the node was highlighted. + * @return true iff the node was highlighted. */ - private boolean highlightAsAttribute(PyQualifiedExpression node, String name) { - LanguageLevel languageLevel = LanguageLevel.forElement(node); + private boolean highlightAsAttribute(@NotNull PyQualifiedExpression node, @NotNull String name) { + final LanguageLevel languageLevel = LanguageLevel.forElement(node); if (PyNames.UnderscoredAttributes.contains(name) || PyNames.getBuiltinMethods(languageLevel).containsKey(name)) { - // things like __len__ - if ( - node.isQualified() // foo.__len__ - || (PyUtil.getConcealingParent(node) instanceof PyClass) // class Foo: ... __len__ = myLenImpl - ) { + // things like __len__: foo.__len__ or class Foo: ... __len__ = my_len_impl + if (node.isQualified() || ScopeUtil.getScopeOwner(node) instanceof PyClass) { final ASTNode astNode = node.getNode(); if (astNode != null) { - ASTNode tgt = astNode.findChildByType(PyTokenTypes.IDENTIFIER); // only the id, not all qualifiers subtree + final ASTNode tgt = astNode.findChildByType(PyTokenTypes.IDENTIFIER); // only the id, not all qualifiers subtree if (tgt != null) { - Annotation ann = getHolder().createInfoAnnotation(tgt, null); + final Annotation ann = getHolder().createInfoAnnotation(tgt, null); ann.setTextAttributes(PyHighlighter.PY_PREDEFINED_USAGE); return true; } @@ -87,5 +83,4 @@ public class PyBuiltinAnnotator extends PyAnnotator { } return false; } - } diff --git a/python/src/icons/PythonIcons.java b/python/src/icons/PythonIcons.java index 2adb29d6c544..4e91858a0969 100644 --- a/python/src/icons/PythonIcons.java +++ b/python/src/icons/PythonIcons.java @@ -49,7 +49,6 @@ public class PythonIcons { public static final Icon Python_24 = load("/icons/com/jetbrains/python/python_24.png"); // 24x24 public static final Icon PythonClosed = load("/icons/com/jetbrains/python/pythonClosed.png"); // 16x16 public static final Icon PythonTests = load("/icons/com/jetbrains/python/pythonTests.png"); // 16x16 - public static final Icon Skeleton = load("/icons/com/jetbrains/python/skeleton.png"); // 16x16 public static final Icon TemplateRoot = load("/icons/com/jetbrains/python/templateRoot.png"); // 16x16 public static final Icon Virtualenv = load("/icons/com/jetbrains/python/virtualenv.png"); // 16x16 diff --git a/python/testData/refactoring/extractsuperclass/properties.after.py b/python/testData/refactoring/extractsuperclass/properties.after.py new file mode 100644 index 000000000000..e512d94e920d --- /dev/null +++ b/python/testData/refactoring/extractsuperclass/properties.after.py @@ -0,0 +1,27 @@ +class ToClass(object): + C = 12 + + def __init__(self): + self.a = 1 + + def _get(self): + return 1 + + def _set(self, value): + pass + + def _delete(self): + pass + + old_property = property(_get, _set, _delete) + + def foo(self): + pass + + +class FromClass(ToClass): + def __init__(self): pass + + + def lala(self): + pass
\ No newline at end of file diff --git a/python/testData/refactoring/extractsuperclass/properties.before.py b/python/testData/refactoring/extractsuperclass/properties.before.py new file mode 100644 index 000000000000..3df31fe9c31f --- /dev/null +++ b/python/testData/refactoring/extractsuperclass/properties.before.py @@ -0,0 +1,22 @@ +class FromClass(object): + C = 12 + + def __init__(self): + self.a = 1 + + def _get(self): + return 1 + + def _set(self, value): + pass + + def _delete(self): + pass + + old_property = property(_get, _set, _delete) + + def foo(self): + pass + + def lala(self): + pass
\ No newline at end of file diff --git a/python/testData/refactoring/pullup/presenter/file.py b/python/testData/refactoring/pullup/presenter/file.py index cb6ca9511209..f70f47e5875c 100644 --- a/python/testData/refactoring/pullup/presenter/file.py +++ b/python/testData/refactoring/pullup/presenter/file.py @@ -30,14 +30,38 @@ class BadMro(MainParent, object, SubParent1, SubParent2): pass class HugeChild(SubParent1, date): #SubParent1 is disabled + __metaclass__ = None # Anyway, this field should be ignored and processed separately as "metaclass", not "class field" + def __init__(self): self.instance_field_1 = 42 self.instance_field_2 = 100500 CLASS_FIELD = 42 (CLASS_FIELD_A,CLASS_FIELD_B) = (42,100500) #We do not support tuples in class assignments for now (see ClassFieldsManager) - def foo(self): #should be disabled + + def _set(self, val): # Should not be treated as method (part of property) pass + + def _get(self): # Should not be treated as method (part of property) + return None + + name = property(fget=_get, fset=_set) + + + @property + def some_property(self): # Should not be treated as method (part of property) + return None + + @some_property.setter + def some_property(self, val): # Should not be treated as method (part of property) + pass + + + + + + def foo(self): #should be disabled + self.some_property = 12 def bar(self): pass diff --git a/python/testData/refactoring/pullup/properties/Class.after.py b/python/testData/refactoring/pullup/properties/Class.after.py new file mode 100644 index 000000000000..1291238ed082 --- /dev/null +++ b/python/testData/refactoring/pullup/properties/Class.after.py @@ -0,0 +1,19 @@ +from SuperClass import SuperClass + + +class AnyClass(SuperClass): + C = 1 + + def __init__(self): + super(AnyClass, self).__init__() + + + + + + + + + def foo(self): + pass + diff --git a/python/testData/refactoring/pullup/properties/Class.py b/python/testData/refactoring/pullup/properties/Class.py new file mode 100644 index 000000000000..5a091a9bd934 --- /dev/null +++ b/python/testData/refactoring/pullup/properties/Class.py @@ -0,0 +1,25 @@ +from SuperClass import SuperClass + + +class AnyClass(SuperClass): + C = 1 + + def __init__(self): + super(AnyClass, self).__init__() + + + @property + def new_property(self): + return 1 + + @new_property.setter + def new_property(self, value): + pass + + @new_property.deleter + def new_property(self): + pass + + def foo(self): + pass + diff --git a/python/testData/refactoring/pullup/properties/SuperClass.after.py b/python/testData/refactoring/pullup/properties/SuperClass.after.py new file mode 100644 index 000000000000..1b2be8de00a9 --- /dev/null +++ b/python/testData/refactoring/pullup/properties/SuperClass.after.py @@ -0,0 +1,15 @@ +class SuperClass(object): + def __init__(self): + pass + + @property + def new_property(self): + return 1 + + @new_property.setter + def new_property(self, value): + pass + + @new_property.deleter + def new_property(self): + pass diff --git a/python/testData/refactoring/pullup/properties/SuperClass.py b/python/testData/refactoring/pullup/properties/SuperClass.py new file mode 100644 index 000000000000..a41b8fdc7db1 --- /dev/null +++ b/python/testData/refactoring/pullup/properties/SuperClass.py @@ -0,0 +1,3 @@ +class SuperClass(object): + def __init__(self): + pass diff --git a/python/testData/refactoring/pullup/pyPullUpInfoModel.py b/python/testData/refactoring/pullup/pyPullUpInfoModel.py index 04f6430f2518..2f891339720c 100644 --- a/python/testData/refactoring/pullup/pyPullUpInfoModel.py +++ b/python/testData/refactoring/pullup/pyPullUpInfoModel.py @@ -15,12 +15,45 @@ class ChildWithDependencies(SomeParent, EmptyParent): CLASS_FIELD_DEPENDS_ON_CLASS_FIELD_FOO = CLASS_FIELD_FOO CLASS_FIELD_DEPENDS_ON_PARENT_FIELD = SomeParent.PARENT_CLASS_FIELD + def __init__(self): SomeParent.__init__(self) self.instance_field_bar = 42 self.depends_on_instance_field_bar = self.instance_field_bar self.depends_on_class_field_foo = ChildWithDependencies.CLASS_FIELD_FOO + + @property + def new_property(self): + return 1 + + def _set_prop(self, val): + pass + + def _get_prop(self): + return 1 + + def _del_prop(self): + pass + + old_property = property(fset=_set_prop) + old_property_2 = property(fget=_get_prop) + old_property_3 = property(fdel=_del_prop) + + + @property + def new_property(self): + return 1 + + @new_property.setter + def new_property(self, val): + pass + + @property + def new_property_2(self): + return 1 + + def normal_method(self): pass @@ -36,4 +69,14 @@ class ChildWithDependencies(SomeParent, EmptyParent): self.normal_method() def method_depends_on_instance_field_bar(self): - eggs = self.instance_field_bar
\ No newline at end of file + eggs = self.instance_field_bar + + def method_depends_on_old_property(self): + i = 12 + self.old_property = i + q = self.old_property_2 + del self.old_property_3 + + def method_depends_on_new_property(self): + self.new_property = 12 + print(self.new_property_2) diff --git a/python/testSrc/com/jetbrains/python/PyEncodingTest.java b/python/testSrc/com/jetbrains/python/PyEncodingTest.java index cccd6d45cfde..608b8396c04a 100644 --- a/python/testSrc/com/jetbrains/python/PyEncodingTest.java +++ b/python/testSrc/com/jetbrains/python/PyEncodingTest.java @@ -15,12 +15,12 @@ */ package com.jetbrains.python; -import junit.framework.TestCase; +import com.jetbrains.python.fixtures.PyTestCase; /** * @author yole */ -public class PyEncodingTest extends TestCase { +public class PyEncodingTest extends PyTestCase { public void testEncodingEmacs() { doTest("#!/usr/bin/python\n# -*- coding: iso-8859-15 -*-\nimport os, sys", "iso-8859-15"); } @@ -33,7 +33,8 @@ public class PyEncodingTest extends TestCase { doTest("#!/usr/local/bin/python\n# coding: latin-1\nimport os, sys", "iso-8859-1"); } - private static void doTest(final String text, final String expected) { - assertEquals(expected, PythonFileType.getCharsetFromEncodingDeclaration(text)); + private void doTest(final String text, final String expected) { + myFixture.configureByText(PythonFileType.INSTANCE, text); + assertEquals(expected, PythonFileType.getCharsetFromEncodingDeclaration(myFixture.getFile())); } } diff --git a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java index 30dc43404a3c..7db230a1d7c1 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java @@ -252,7 +252,7 @@ public class PyTypeParserTest extends PyTestCase { final PyCallableType callableType = (PyCallableType)type; assertNotNull(callableType); final TypeEvalContext context = getTypeEvalContext(); - final PyType returnType = callableType.getCallType(context, null); + final PyType returnType = callableType.getReturnType(context); assertInstanceOf(returnType, PyGenericType.class); final List<PyCallableParameter> parameterTypes = callableType.getParameters(context); assertNotNull(parameterTypes); @@ -271,7 +271,7 @@ public class PyTypeParserTest extends PyTestCase { assertInstanceOf(type, PyCallableType.class); final PyCallableType callableType = (PyCallableType)type; assertNotNull(callableType); - final PyType returnType = callableType.getCallType(getTypeEvalContext(), null); + final PyType returnType = callableType.getReturnType(getTypeEvalContext()); assertNotNull(returnType); assertEquals("int", returnType.getName()); final List<PyCallableParameter> parameterTypes = callableType.getParameters(getTypeEvalContext()); diff --git a/python/testSrc/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassTest.java b/python/testSrc/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassTest.java index 13d5b4d4f253..c96bdc2397e1 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassTest.java @@ -125,6 +125,11 @@ public class PyExtractSuperclassTest extends PyClassRefactoringTest { doSimpleTest("FromClass", "ToClass", null, true, "#instance_field", "#CLASS_FIELD"); } + + public void testProperties() throws Exception { + doSimpleTest("FromClass", "ToClass", null, true, "#C", "#a", "._get", ".foo"); + } + private void doSimpleTest(final String className, final String superclassName, final String expectedError, diff --git a/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpInfoModelTest.java b/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpInfoModelTest.java index 9fe02c302c9a..3e5e508901d7 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpInfoModelTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpInfoModelTest.java @@ -69,6 +69,27 @@ public class PyPullUpInfoModelTest extends PyTestCase { Assert.assertThat("Instance on member dependencies failed", getErrorMemberNames(), Matchers.containsInAnyOrder("self.instance_field_bar")); } + /** + * Check dependnecies for properties, declared in old-style + * + */ + public void testOldProperty() throws Exception { + checkMembers("method_depends_on_old_property(self)"); + Assert.assertThat("Method on old property dependency failed", getErrorMemberNames(), Matchers.containsInAnyOrder( + "old_property", + "old_property_2", + "old_property_3")); + } + + /** + * + * Check dependnecies for properties, declared in new-style + */ + public void testNewProperty() throws Exception { + checkMembers("method_depends_on_new_property(self)"); + Assert.assertThat("Method on new property dependency failed", getErrorMemberNames(), Matchers.containsInAnyOrder("new_property", "new_property_2")); + } + /** * All dependencies are met: new (destination) class has all of them diff --git a/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterTest.java b/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterTest.java index ee5371cf24b4..1ee20d27f62a 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterTest.java @@ -144,7 +144,9 @@ public class PyPullUpPresenterTest extends PyRefactoringPresenterTestCase<PyPull new PyPresenterTestMemberEntry("static_2()", true, true, py3K), new PyPresenterTestMemberEntry("self.instance_field_1", true, false, false), new PyPresenterTestMemberEntry("self.instance_field_2", true, false, false), - new PyPresenterTestMemberEntry("bad_method()", true, false, true)); + new PyPresenterTestMemberEntry("bad_method()", true, false, true), + new PyPresenterTestMemberEntry("name", true, false, false), + new PyPresenterTestMemberEntry("some_property", true, false, false)); compareMembers(memberNamesAndStatus, matcher); } diff --git a/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpTest.java b/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpTest.java index d725c1736083..fbf568807e40 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpTest.java @@ -97,6 +97,13 @@ public class PyPullUpTest extends PyClassRefactoringTest { doMultiFileTest(); } + public void testProperties() { + final String[] modules = {"Class", "SuperClass"}; + configureMultiFile(modules); + doPullUp("AnyClass", "SuperClass", ".new_property"); + checkMultiFile(modules); + } + public void testFieldMove() { final String[] modules = {"Class", "SuperClass"}; configureMultiFile(modules); diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 57e0ec144aec..1a08b7c57386 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -320,10 +320,10 @@ class.filters.dialog.exclusion.filters.group=Class Exclusion Filters instance.filters.dialog.title=Instance Filters instance.filters.dialog.instance.filters.group=Instance Filters breakpoint.exception.breakpoint.display.name=''{0}'' -exception.breakpoints.tab.title=Exception Breakpoints -field.watchpoints.tab.title=Field Watchpoints -line.breakpoints.tab.title=Line Breakpoints -method.breakpoints.tab.title=Method Breakpoints +exception.breakpoints.tab.title=Java Exception Breakpoints +field.watchpoints.tab.title=Java Field Watchpoints +line.breakpoints.tab.title=Java Line Breakpoints +method.breakpoints.tab.title=Java Method Breakpoints title.error.evaluating.breakpoint.condition=Breakpoint Condition Error title.error.evaluating.breakpoint.action=Breakpoint Action Error error.evaluating.breakpoint.condition.or.action=Problem processing VM event:\nBreakpoint: ''{0}''\nError: {1}\nWould you like to stop at the breakpoint? @@ -446,5 +446,3 @@ error.corrupt.debug.info=Debug info might be corrupt: {0} action.kill.process.text=Kill Process action.kill.process.description=Forcibly terminate debugged application evaluation.error.unknown.method.return.type=Cannot resolve method return type: {0} - -java.breakpoint.title=Java Line Breakpoints diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index d04e05907fa8..ff39c265a942 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -86,9 +86,6 @@ <extensionPoint name="debugger.nodeRenderer" interface="com.intellij.debugger.ui.tree.render.NodeRenderer"/> - <extensionPoint name="debugger.breakpointFactory" - interface="com.intellij.debugger.ui.breakpoints.BreakpointFactory"/> - <extensionPoint name="debugger.jvmDebugProvider" interface="com.intellij.debugger.engine.JVMDebugProvider"/> @@ -627,7 +624,7 @@ groupName="Java language level migration aids" enabledByDefault="true" level="WARNING" implementationClass="com.intellij.codeInspection.AnonymousCanBeLambdaInspection" /> <localInspection language="JAVA" shortName="Convert2streamapi" displayName="foreach loop can be collapsed with stream api" - groupName="Java language level migration aids" enabledByDefault="true" level="WARNING" implementationClass="com.intellij.codeInspection.StreamApiMigrationInspection"/> + groupName="Java language level migration aids" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.intellij.codeInspection.StreamApiMigrationInspection"/> <localInspection language="JAVA" shortName="Anonymous2MethodRef" displayName="Anonymous type can be replaced with method reference" groupName="Java language level migration aids" enabledByDefault="true" level="WARNING" implementationClass="com.intellij.codeInspection.AnonymousCanBeMethodReferenceInspection" /> @@ -1378,11 +1375,11 @@ <resolveScopeEnlarger implementation="com.intellij.psi.NonClasspathResolveScopeEnlarger"/> <xdebugger.debuggerSupport implementation="com.intellij.debugger.ui.JavaDebuggerSupport"/> - <debugger.breakpointFactory implementation="com.intellij.debugger.ui.breakpoints.LineBreakpointFactory"/> - <debugger.breakpointFactory implementation="com.intellij.debugger.ui.breakpoints.ExceptionBreakpointFactory"/> - <debugger.breakpointFactory implementation="com.intellij.debugger.ui.breakpoints.AnyExceptionBreakpointFactory"/> - <debugger.breakpointFactory implementation="com.intellij.debugger.ui.breakpoints.FieldBreakpointFactory"/> - <debugger.breakpointFactory implementation="com.intellij.debugger.ui.breakpoints.MethodBreakpointFactory"/> + <xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaMethodBreakpointType"/> + <xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaWildcardMethodBreakpointType"/> + <xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaFieldBreakpointType"/> + <xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaExceptionBreakpointType"/> + <xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType"/> <debugger.jvmSmartStepIntoHandler implementation="com.intellij.debugger.actions.JavaSmartStepIntoHandler"/> <applicationService serviceInterface="com.intellij.remoteServer.runtime.deployment.debug.JavaDebuggerLauncher" @@ -1461,8 +1458,6 @@ <codeInsight.unresolvedReferenceQuickFixProvider implementation="com.intellij.jarFinder.FindJarQuickFixProvider"/> - <xdebugger.breakpointType implementation="org.jetbrains.java.debugger.breakpoints.JavaBreakpointType"/> - <refactoring.pullUpHelperFactory language="JAVA" implementationClass="com.intellij.refactoring.memberPullUp.JavaPullUpHelperFactory"/> <hierarchy.referenceProcessor implementation="com.intellij.ide.hierarchy.call.JavaCallReferenceProcessor"/> <projectTemplate projectType="JAVA_MODULE" templatePath="resources/projectTemplates/Java/Command_Line_App.zip"/> diff --git a/spellchecker/src/com/intellij/spellchecker/english.dic b/spellchecker/src/com/intellij/spellchecker/english.dic index 169e4c20e7ab..0047044678a5 100644 --- a/spellchecker/src/com/intellij/spellchecker/english.dic +++ b/spellchecker/src/com/intellij/spellchecker/english.dic @@ -68545,6 +68545,7 @@ funding fundraiser fundraisers funds +fundraising funeral funeral's funerals diff --git a/updater/src/com/intellij/updater/Runner.java b/updater/src/com/intellij/updater/Runner.java index 9a88ea491eeb..d0143a946b0c 100755 --- a/updater/src/com/intellij/updater/Runner.java +++ b/updater/src/com/intellij/updater/Runner.java @@ -24,15 +24,13 @@ public class Runner { private static final String NEW_BUILD_DESCRIPTION = "new.build.description"; public static void main(String[] args) throws Exception { - if (args.length >= 7 && "create".equals(args[0])) { + if (args.length >= 6 && "create".equals(args[0])) { String oldVersionDesc = args[1]; String newVersionDesc = args[2]; String oldFolder = args[3]; String newFolder = args[4]; String patchFile = args[5]; - - String logFolder = args[6]; - initLogger(logFolder); + initLogger(); List<String> ignoredFiles = extractFiles(args, "ignored"); List<String> criticalFiles = extractFiles(args, "critical"); @@ -40,8 +38,7 @@ public class Runner { create(oldVersionDesc, newVersionDesc, oldFolder, newFolder, patchFile, ignoredFiles, criticalFiles, optionalFiles); } else if (args.length >= 2 && "install".equals(args[0])) { - // install [--exit0] <destination_folder> [log_directory] - int max = 3; + // install [--exit0] <destination_folder> int nextArg = 1; // Default install exit code is SwingUpdaterUI.RESULT_REQUIRES_RESTART (42) unless overridden to be 0. @@ -50,13 +47,10 @@ public class Runner { if (args[nextArg].equals("--exit0")) { useExitCode0 = true; nextArg++; - max++; } String destFolder = args[nextArg++]; - - String logFolder = args.length >= max ? args[nextArg] : null; - initLogger(logFolder); + initLogger(); logger.info("destFolder: " + destFolder); install(useExitCode0, destFolder); @@ -72,7 +66,8 @@ public class Runner { return fileLogDir.isDirectory() && fileLogDir.canWrite() && fileLogDir.getUsableSpace() >= 1000000; } - private static String getLogDir(String logFolder) { + private static String getLogDir() { + String logFolder = System.getProperty("idea.updater.log"); if (logFolder == null || !isValidLogDir(logFolder)) { logFolder = System.getProperty("java.io.tmpdir"); if (!isValidLogDir(logFolder)) { @@ -82,9 +77,9 @@ public class Runner { return logFolder; } - public static void initLogger(String logFolder) { + public static void initLogger() { if (logger == null) { - logFolder = getLogDir(logFolder); + String logFolder = getLogDir(); FileAppender update = new FileAppender(); update.setFile(new File(logFolder, "idea_updater.log").getAbsolutePath()); @@ -97,7 +92,6 @@ public class Runner { updateError.setFile(new File(logFolder, "idea_updater_error.log").getAbsolutePath()); updateError.setLayout(new PatternLayout("%d{dd MMM yyyy HH:mm:ss} %-5p %C{1}.%M - %m%n")); updateError.setThreshold(Level.ERROR); - // The error(s) from an old run of the updater (if there were) could be found in idea_updater.log file updateError.setAppend(false); updateError.activateOptions(); @@ -239,17 +233,20 @@ public class Runner { in.close(); } - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } - catch (Exception ignore) { - printStackTrace(ignore); + // todo[r.sh] to delete in IDEA 14 (after a full circle of platform updates) + if (System.getProperty("swing.defaultlaf") == null) { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception ignore) { + printStackTrace(ignore); + } } - } - }); + }); + } new SwingUpdaterUI(props.getProperty(OLD_BUILD_DESCRIPTION), props.getProperty(NEW_BUILD_DESCRIPTION), diff --git a/updater/testSrc/com/intellij/updater/DigesterTest.java b/updater/testSrc/com/intellij/updater/DigesterTest.java index a7ec965359ee..3b524f8288e9 100644 --- a/updater/testSrc/com/intellij/updater/DigesterTest.java +++ b/updater/testSrc/com/intellij/updater/DigesterTest.java @@ -10,12 +10,12 @@ import static org.junit.Assert.assertEquals; public class DigesterTest extends UpdaterTestCase { @Test public void testBasics() throws Exception { + Runner.initLogger(); Map<String, Long> checkSums = Digester.digestFiles(getDataDir(), Collections.<String>emptyList(), TEST_UI); assertEquals(12, checkSums.size()); assertEquals(CHECKSUMS.README_TXT, (long)checkSums.get("Readme.txt")); assertEquals(CHECKSUMS.FOCUSKILLER_DLL, (long)checkSums.get("bin/focuskiller.dll")); assertEquals(CHECKSUMS.BOOTSTRAP_JAR, (long)checkSums.get("lib/bootstrap.jar")); - Runner.initLogger(System.getProperty("java.io.tmpdir")); } }
\ No newline at end of file diff --git a/updater/testSrc/com/intellij/updater/RunnerTest.java b/updater/testSrc/com/intellij/updater/RunnerTest.java index 4813db1711b3..22464a0fa053 100644 --- a/updater/testSrc/com/intellij/updater/RunnerTest.java +++ b/updater/testSrc/com/intellij/updater/RunnerTest.java @@ -11,7 +11,7 @@ public class RunnerTest extends UpdaterTestCase { @Test public void testExtractingFiles() throws Exception { String[] args = {"bar", "ignored=xxx;yyy;zzz/zzz", "critical=", "ignored=aaa", "baz", "critical=ccc"}; - Runner.initLogger(System.getProperty("java.io.tmpdir")); + Runner.initLogger(); assertEquals(Arrays.asList("xxx", "yyy", "zzz/zzz", "aaa"), Runner.extractFiles(args, "ignored")); diff --git a/updater/testSrc/com/intellij/updater/UpdaterTestCase.java b/updater/testSrc/com/intellij/updater/UpdaterTestCase.java index 82d7bbe860c7..dea5fbdd7c6d 100644 --- a/updater/testSrc/com/intellij/updater/UpdaterTestCase.java +++ b/updater/testSrc/com/intellij/updater/UpdaterTestCase.java @@ -25,7 +25,7 @@ public abstract class UpdaterTestCase { @Before public void setUp() throws Exception { - Runner.initLogger(System.getProperty("java.io.tmpdir")); + Runner.initLogger(); myTempDirFixture = IdeaTestFixtureFactory.getFixtureFactory().createTempDirTestFixture(); myTempDirFixture.setUp(); diff --git a/xml/dom-impl/src/com/intellij/util/xml/DomFileIndex.java b/xml/dom-impl/src/com/intellij/util/xml/DomFileIndex.java index 493f6a50ccda..7ca36a62c2f2 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/DomFileIndex.java +++ b/xml/dom-impl/src/com/intellij/util/xml/DomFileIndex.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. @@ -84,11 +84,13 @@ public class DomFileIndex extends ScalarIndexExtension<String>{ return myDataIndexer; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return new EnumeratorStringDescriptor(); } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomApplicationComponent.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomApplicationComponent.java index f99567085e8e..c2687fddc860 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomApplicationComponent.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomApplicationComponent.java @@ -96,8 +96,10 @@ public class DomApplicationComponent { public int getCumulativeVersion() { int result = 0; for (DomFileDescription description : getAllFileDescriptions()) { - result += description.getVersion(); - result += description.getRootTagName().hashCode(); // so that a plugin enabling/disabling could trigger the reindexing + if (description.hasStubs()) { + result += description.getStubVersion(); + result += description.getRootTagName().hashCode(); // so that a plugin enabling/disabling could trigger the reindexing + } } return result; } diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlCompletionData.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlCompletionData.java index 4249986cf002..8446e8872b58 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/XmlCompletionData.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlCompletionData.java @@ -218,8 +218,9 @@ public class XmlCompletionData extends CompletionData { containingFile = (XmlFile)document.getContainingFile(); final FileType ft = containingFile.getFileType(); - - if(ft != StdFileTypes.XML) { + if (HtmlUtil.isHtml5Document(document)) { + descriptorFile = XmlUtil.findXmlFile(containingFile, Html5SchemaProvider.getCharsDtdLocation()); + } else if(ft != StdFileTypes.XML) { final String namespace = ft == StdFileTypes.XHTML || ft == StdFileTypes.JSPX ? XmlUtil.XHTML_URI : XmlUtil.HTML_URI; final XmlNSDescriptor nsDescriptor = document.getDefaultNSDescriptor(namespace, true); diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/HtmlSelectioner.java b/xml/impl/src/com/intellij/codeInsight/editorActions/HtmlSelectioner.java index e724f7b1945e..be9035661247 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/HtmlSelectioner.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/HtmlSelectioner.java @@ -32,6 +32,7 @@ import com.intellij.lang.Language; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.UnfairTextRange; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -107,8 +108,8 @@ public class HtmlSelectioner extends AbstractWordSelectioner { final ASTNode tagStartEnd = XmlChildRole.START_TAG_END_FINDER.findChild(tag.getNode()); final ASTNode tagEndStart = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(tag.getNode()); if (tagStartEnd != null && tagEndStart != null) { - result.add(new TextRange(tagStartEnd.getTextRange().getEndOffset(), - tagEndStart.getTextRange().getStartOffset())); + result.add(new UnfairTextRange(tagStartEnd.getTextRange().getEndOffset(), + tagEndStart.getTextRange().getStartOffset())); } if (tagStartEnd != null) { result.add(new TextRange(tag.getTextRange().getStartOffset(), diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java index 922d910dffc2..e483f34b61c5 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.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. @@ -18,31 +18,34 @@ package com.intellij.codeInsight.editorActions; import com.intellij.application.options.editor.WebEditorOptions; import com.intellij.codeInsight.AutoPopupController; import com.intellij.lang.xml.XMLLanguage; +import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlAttribute; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import java.util.List; + public class XmlEqTypedHandler extends TypedHandlerDelegate { - private boolean needToInsertQuotes = false; + private List<Caret> caretsForInsertingQuotes = ContainerUtil.newSmartList(); @Override - public Result beforeCharTyped(char c, - Project project, - Editor editor, - PsiFile file, - FileType fileType) { + public Result beforeCharTyped(char c, Project project, Editor editor, PsiFile file, FileType fileType) { if (WebEditorOptions.getInstance().isInsertQuotesForAttributeValue()) { boolean inXml = file.getLanguage() instanceof XMLLanguage || file.getViewProvider().getBaseLanguage() instanceof XMLLanguage; if (c == '=' && inXml) { - int offset = editor.getCaretModel().getOffset(); - PsiElement at = file.findElementAt(offset - 1); - PsiElement atParent = at != null ? at.getParent() : null; - needToInsertQuotes = atParent instanceof XmlAttribute && ((XmlAttribute)atParent).getValueElement() == null; + for(Caret caret : editor.getCaretModel().getAllCarets()) { + PsiElement at = file.findElementAt(caret.getOffset() - 1); + PsiElement atParent = at != null ? at.getParent() : null; + if(atParent instanceof XmlAttribute && ((XmlAttribute)atParent).getValueElement() == null) { + caretsForInsertingQuotes.add(caret); + } + } } } @@ -51,13 +54,14 @@ public class XmlEqTypedHandler extends TypedHandlerDelegate { @Override public Result charTyped(char c, Project project, @NotNull Editor editor, @NotNull PsiFile file) { - if (needToInsertQuotes) { - int offset = editor.getCaretModel().getOffset(); - editor.getDocument().insertString(offset, "\"\""); - editor.getCaretModel().moveToOffset(offset + 1); + for (Caret caret : caretsForInsertingQuotes) { + editor.getDocument().insertString(caret.getOffset(), "\"\""); + caret.moveCaretRelatively(1, 0, false, true); + } + if (editor.getCaretModel().getAllCarets().size() == caretsForInsertingQuotes.size()) { AutoPopupController.getInstance(project).scheduleAutoPopup(editor); } - needToInsertQuotes = false; + caretsForInsertingQuotes.clear(); return super.charTyped(c, project, editor, file); } } diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlGtTypedHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlGtTypedHandler.java index e76b5a3447e2..fcebe19a8f67 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlGtTypedHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlGtTypedHandler.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. @@ -20,7 +20,9 @@ import com.intellij.codeInsight.highlighting.BraceMatchingUtil; import com.intellij.lang.ASTNode; import com.intellij.lang.xml.XMLLanguage; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorModificationUtil; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.HighlighterIterator; @@ -37,12 +39,15 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.*; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import com.intellij.xml.XmlElementDescriptor; import com.intellij.xml.XmlElementDescriptorWithCDataContent; import com.intellij.xml.util.HtmlUtil; import com.intellij.xml.util.XmlUtil; import org.jetbrains.annotations.NonNls; +import java.util.Collection; + public class XmlGtTypedHandler extends TypedHandlerDelegate { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.editorActions.TypedHandler"); @@ -88,9 +93,8 @@ public class XmlGtTypedHandler extends TypedHandlerDelegate { } if (tokenType == XmlTokenType.XML_TAG_END || - tokenType == XmlTokenType.XML_EMPTY_ELEMENT_END && element.getTextOffset() == offset - 1 - ) { - editor.getCaretModel().moveToOffset(offset + 1); + tokenType == XmlTokenType.XML_EMPTY_ELEMENT_END && element.getTextOffset() == offset - 1) { + EditorModificationUtil.moveAllCaretsRelatively(editor, 1); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); return Result.STOP; } @@ -149,10 +153,9 @@ public class XmlGtTypedHandler extends TypedHandlerDelegate { if (!(element instanceof XmlTag)) { if (element instanceof XmlTokenImpl && element.getPrevSibling() !=null && - element.getPrevSibling().getText().equals("<") - ) { + element.getPrevSibling().getText().equals("<")) { // tag is started and there is another text in the end - editor.getDocument().insertString(offset, "</" + element.getText() + ">"); + EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, "</" + element.getText() + ">", false, 0); } return Result.CONTINUE; } @@ -230,36 +233,38 @@ public class XmlGtTypedHandler extends TypedHandlerDelegate { if (hasBalance) return Result.CONTINUE; } - TextRange cdataReformatRange = null; + Collection<TextRange> cdataReformatRanges = null; final XmlElementDescriptor descriptor = tag.getDescriptor(); if (descriptor instanceof XmlElementDescriptorWithCDataContent) { final XmlElementDescriptorWithCDataContent cDataContainer = (XmlElementDescriptorWithCDataContent)descriptor; + cdataReformatRanges = ContainerUtil.newSmartList(); if (cDataContainer.requiresCdataBracesInContext(tag)) { - int rangeStart = offset; @NonNls final String cDataStart = "><![CDATA["; final String inserted = cDataStart + "\n]]>"; - editor.getDocument().insertString(offset, inserted); - final int newoffset = offset + cDataStart.length(); - editor.getCaretModel().moveToOffset(newoffset); - offset += inserted.length(); - cdataReformatRange = new TextRange(rangeStart, offset + 1); + EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, inserted, false, cDataStart.length()); + for (Caret caret : editor.getCaretModel().getAllCarets()) { + int caretOffset = caret.getOffset(); + if (caretOffset >= cDataStart.length()) { + cdataReformatRanges.add(TextRange.from(caretOffset - cDataStart.length(), inserted.length())); + } + } } } - editor.getDocument().insertString(offset, "</" + name + ">"); + EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, "</" + name + ">", false, 0); - if (cdataReformatRange != null) { + if (cdataReformatRanges != null && !cdataReformatRanges.isEmpty()) { PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); try { - CodeStyleManager.getInstance(project).reformatText(file, cdataReformatRange.getStartOffset(), cdataReformatRange.getEndOffset()); + CodeStyleManager.getInstance(project).reformatText(file, cdataReformatRanges); } catch (IncorrectOperationException e) { LOG.error(e); } } - return cdataReformatRange != null ? Result.STOP : Result.CONTINUE; + return cdataReformatRanges != null && !cdataReformatRanges.isEmpty() ? Result.STOP : Result.CONTINUE; } return Result.CONTINUE; } diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.java index 35e772737b81..9824d444557d 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.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. @@ -39,6 +39,7 @@ public class XmlSlashTypedHandler extends TypedHandlerDelegate implements XmlTok PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); final int offset = editor.getCaretModel().getOffset(); + if (file == null) return Result.CONTINUE; FileViewProvider provider = file.getViewProvider(); PsiElement element = provider.findElementAt(offset, XMLLanguage.class); @@ -71,6 +72,7 @@ public class XmlSlashTypedHandler extends TypedHandlerDelegate implements XmlTok PsiDocumentManager.getInstance(project).commitAllDocuments(); PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); + if (file == null) return Result.CONTINUE; FileViewProvider provider = file.getViewProvider(); final int offset = editor.getCaretModel().getOffset(); PsiElement element = provider.findElementAt(offset - 1, XMLLanguage.class); @@ -91,7 +93,7 @@ public class XmlSlashTypedHandler extends TypedHandlerDelegate implements XmlTok tag = tag1; } } - EditorModificationUtil.insertStringAtCaret(editor, tag.getName() + ">"); + EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, tag.getName() + ">", false); return Result.STOP; } } @@ -100,7 +102,7 @@ public class XmlSlashTypedHandler extends TypedHandlerDelegate implements XmlTok while((prevLeaf = TreeUtil.prevLeaf(prevLeaf)) != null && prevLeaf.getElementType() == XmlTokenType.XML_WHITE_SPACE); if(prevLeaf instanceof OuterLanguageElement) { element = file.getViewProvider().findElementAt(offset - 1, file.getLanguage()); - prevLeaf = element.getNode(); + prevLeaf = element != null ? element.getNode() : null; while((prevLeaf = TreeUtil.prevLeaf(prevLeaf)) != null && prevLeaf.getElementType() == XmlTokenType.XML_WHITE_SPACE); } if(prevLeaf == null) return Result.CONTINUE; @@ -118,7 +120,7 @@ public class XmlSlashTypedHandler extends TypedHandlerDelegate implements XmlTok if (XmlUtil.getTokenOfType(tag, XmlTokenType.XML_EMPTY_ELEMENT_END) != null) return Result.CONTINUE; if (PsiTreeUtil.getParentOfType(element, XmlAttributeValue.class) != null) return Result.CONTINUE; - EditorModificationUtil.insertStringAtCaret(editor, ">"); + EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, ">", false); return Result.STOP; } return Result.CONTINUE; diff --git a/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java b/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java index ed0538bf6820..984bd4997ba0 100644 --- a/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java +++ b/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.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. @@ -86,16 +86,18 @@ public class Html5CustomAttributesIndex extends ScalarIndexExtension<String> { return myIndexer; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return new EnumeratorStringDescriptor(); } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.HTML, StdFileTypes.XHTML) { @Override - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { return file.isInLocalFileSystem(); } }; diff --git a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java index cd62adf16f1d..1b2fabde81b3 100644 --- a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java +++ b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.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. @@ -26,6 +26,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.editor.colors.EditorFontType; +import com.intellij.openapi.editor.event.CaretAdapter; import com.intellij.openapi.editor.event.CaretEvent; import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.extensions.Extensions; @@ -103,7 +104,7 @@ public class BreadcrumbsXmlWrapper implements BreadcrumbsItemListener<Breadcrumb myInfoProvider = findInfoProvider(findViewProvider(myFile, myProject)); - final CaretListener caretListener = new CaretListener() { + final CaretListener caretListener = new CaretAdapter() { public void caretPositionChanged(final CaretEvent e) { if (myUserCaretChange) { queueUpdate(editor); diff --git a/xml/impl/src/com/intellij/xml/index/SchemaTypeInheritanceIndex.java b/xml/impl/src/com/intellij/xml/index/SchemaTypeInheritanceIndex.java index 515522185339..f504b66ba754 100644 --- a/xml/impl/src/com/intellij/xml/index/SchemaTypeInheritanceIndex.java +++ b/xml/impl/src/com/intellij/xml/index/SchemaTypeInheritanceIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -133,11 +133,12 @@ public class SchemaTypeInheritanceIndex extends XmlIndex<Set<SchemaTypeInfo>> { }; } + @NotNull @Override public DataExternalizer<Set<SchemaTypeInfo>> getValueExternalizer() { return new DataExternalizer<Set<SchemaTypeInfo>>() { @Override - public void save(DataOutput out, Set<SchemaTypeInfo> value) throws IOException { + public void save(@NotNull DataOutput out, Set<SchemaTypeInfo> value) throws IOException { out.writeInt(value.size()); for (SchemaTypeInfo key : value) { out.writeUTF(key.getNamespaceUri()); @@ -147,7 +148,7 @@ public class SchemaTypeInheritanceIndex extends XmlIndex<Set<SchemaTypeInfo>> { } @Override - public Set<SchemaTypeInfo> read(DataInput in) throws IOException { + public Set<SchemaTypeInfo> read(@NotNull DataInput in) throws IOException { final Set<SchemaTypeInfo> set = new HashSet<SchemaTypeInfo>(); final int size = in.readInt(); for (int i = 0; i < size; i++) { diff --git a/xml/impl/src/com/intellij/xml/index/XmlTagNamesIndex.java b/xml/impl/src/com/intellij/xml/index/XmlTagNamesIndex.java index 97fb7c0d3d53..b3fc55c1a857 100644 --- a/xml/impl/src/com/intellij/xml/index/XmlTagNamesIndex.java +++ b/xml/impl/src/com/intellij/xml/index/XmlTagNamesIndex.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. @@ -70,6 +70,7 @@ public class XmlTagNamesIndex extends XmlIndex<Void> { }; } + @NotNull @Override public DataExternalizer<Void> getValueExternalizer() { return ScalarIndexExtension.VOID_DATA_EXTERNALIZER; diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java index eede27a5a2b9..a00d40dd1172 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java @@ -1,3 +1,18 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.intellij.plugins.relaxNG.model.resolve; import com.intellij.ide.highlighter.XmlFileType; @@ -129,16 +144,18 @@ public class RelaxSymbolIndex extends ScalarIndexExtension<String> { }; } + @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return new EnumeratorStringDescriptor(); } + @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML, RncFileType.getInstance()) { @Override - public boolean acceptInput(VirtualFile file) { + public boolean acceptInput(@NotNull VirtualFile file) { return !(file.getFileSystem() instanceof JarFileSystem); } }; diff --git a/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java b/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java index 6c4b73f1789c..93967d26baea 100644 --- a/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java +++ b/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.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. @@ -17,6 +17,7 @@ package com.intellij.codeInsight.completion; import com.intellij.application.options.editor.WebEditorOptions; import com.intellij.ide.highlighter.XmlFileType; +import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; /** @@ -24,16 +25,75 @@ import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCa * Date: 30.08.13 */ public class XmlTypedHandlersTest extends LightPlatformCodeInsightFixtureTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + EditorTestUtil.enableMultipleCarets(); + } + + @Override + protected void tearDown() throws Exception { + EditorTestUtil.disableMultipleCarets(); + super.tearDown(); + } - public void testClosingTag() throws Exception { + public void testClosingTag() { doTest("<foo><<caret>", '/', "<foo></foo>"); } + public void testValueQuotesWithMultiCarets() { + doTest("<foo bar<caret>><foo bar<caret>>", '=', "<foo bar=\"<caret>\"><foo bar=\"<caret>\">"); + } + + public void testValueQuotesWithMultiCaretsWithDifferentContexts() { + doTest("<foo bar <caret>><foo bar<caret>>", '=', "<foo bar =<caret>><foo bar=\"<caret>\">"); + } + + public void testCloseTagOnSlashWithMultiCarets() { + doTest("<bar>\n" + + "<foo><<caret>\n" + + "<foo><<caret>\n" + + "</bar>", '/', "<bar>\n" + + "<foo></foo><caret>\n" + + "<foo></foo><caret>\n" + + "</bar>"); + } + + public void testCloseTagOnGtWithMultiCarets() { + doTest("<bar>\n" + + "<foo<caret>\n" + + "<foo<caret>\n" + + "</bar>", '>', "<bar>\n" + + "<foo><caret></foo>\n" + + "<foo><caret></foo>\n" + + "</bar>"); + } + + public void _testCloseTagOnSlashWithMultiCaretsInDifferentContexts() { + doTest("<bar>\n" + + "<foo><<caret>\n" + + "<fiz><<caret>\n" + + "</bar>", '/', "<bar>\n" + + "<foo></foo><caret>\n" + + "<fiz></fiz><caret>\n" + + "</bar>"); + } + + public void _testCloseTagOnGtWithMultiCaretsInDifferentContexts() { + doTest("<bar>\n" + + "<foo<caret>\n" + + "<fiz<caret>\n" + + "</bar>", '>', "<bar>\n" + + "<foo><caret></foo>\n" + + "<fiz><caret></fiz>\n" + + "</bar>"); + } + public void testGreedyClosing() { doTest("<foo><<caret>foo>", '/', "<foo></foo>"); } - public void testValueQuotas() throws Exception { + public void testValueQuotas() { doTest("<foo bar<caret>", '=', "<foo bar=\"<caret>\""); WebEditorOptions.getInstance().setInsertQuotesForAttributeValue(false); try { diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java index 4d58a5524bfe..d5bec52f6091 100644 --- a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java @@ -514,18 +514,23 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx { if (classLoader == null && clazz == null) return file; final URL resource = clazz == null ? classLoader.getResource(file) : clazz.getResource(file); - classLoader = null; - clazz = null; - if (resource == null) { - String message = "Cannot find standard resource. filename:" + file + " class=" + classLoader; - if (ApplicationManager.getApplication().isUnitTestMode()) { - LOG.error(message); - } - else { - LOG.warn(message); - } - return null; + try { + if (resource == null) { + String message = "Cannot find standard resource. filename:" + file + " class=" + clazz + ", classLoader:" + classLoader; + if (ApplicationManager.getApplication().isUnitTestMode()) { + LOG.error(message); + } + else { + LOG.warn(message); + } + + return null; + } + } + finally { + classLoader = null; + clazz = null; } String path = FileUtil.unquote(resource.toString()); @@ -535,7 +540,6 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx { return path; } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/xml/xml-psi-impl/src/com/intellij/lang/html/HtmlParsing.java b/xml/xml-psi-impl/src/com/intellij/lang/html/HtmlParsing.java index 250d27e9a101..55ab6d28fdd8 100644 --- a/xml/xml-psi-impl/src/com/intellij/lang/html/HtmlParsing.java +++ b/xml/xml-psi-impl/src/com/intellij/lang/html/HtmlParsing.java @@ -76,7 +76,10 @@ public class HtmlParsing { error = flushError(error); parseProcessingInstruction(); } - else if (tt == XmlTokenType.XML_REAL_WHITE_SPACE || tt == XmlTokenType.XML_CHAR_ENTITY_REF || tt == XmlTokenType.XML_DATA_CHARACTERS) { + else if (tt == XmlTokenType.XML_CHAR_ENTITY_REF || tt == XmlTokenType.XML_ENTITY_REF_TOKEN) { + parseReference(); + } + else if (tt == XmlTokenType.XML_REAL_WHITE_SPACE || tt == XmlTokenType.XML_DATA_CHARACTERS) { error = flushError(error); advance(); } else if (tt == XmlTokenType.XML_END_TAG_START) { diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlEntityRefImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlEntityRefImpl.java index e666cdcea090..8bd39976fe44 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlEntityRefImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlEntityRefImpl.java @@ -152,27 +152,28 @@ public class XmlEntityRefImpl extends XmlElementImpl implements XmlEntityRef { ) { XmlDocument document = ((XmlFile)targetElement).getDocument(); final XmlTag rootTag = document.getRootTag(); + XmlFile descriptorFile = null; - if (rootTag != null && document.getUserData(DISABLE_ENTITY_EXPAND) == null) { + if (HtmlUtil.isHtml5Document(document)) { + descriptorFile = XmlUtil.findXmlFile((XmlFile)targetElement, Html5SchemaProvider.getCharsDtdLocation()); + } else if (rootTag != null && document.getUserData(DISABLE_ENTITY_EXPAND) == null) { final XmlElementDescriptor descriptor = rootTag.getDescriptor(); if (descriptor != null && !(descriptor instanceof AnyXmlElementDescriptor)) { - PsiElement element = !HtmlUtil.isHtml5Context(rootTag) ? descriptor.getDeclaration() : - XmlUtil.findXmlFile((XmlFile)targetElement, Html5SchemaProvider.getCharsDtdLocation()); + PsiElement element = descriptor.getDeclaration(); final PsiFile containingFile = element != null ? element.getContainingFile():null; - final XmlFile descriptorFile = containingFile instanceof XmlFile ? (XmlFile)containingFile:null; - - if (descriptorFile != null && - !descriptorFile.getName().equals(((XmlFile)targetElement).getName()+".dtd")) { - deps.add(descriptorFile); - XmlUtil.processXmlElements( - descriptorFile, - processor, - true - ); - } + descriptorFile = containingFile instanceof XmlFile ? (XmlFile)containingFile:null; } } + if (descriptorFile != null && + !descriptorFile.getName().equals(((XmlFile)targetElement).getName() + ".dtd")) { + deps.add(descriptorFile); + XmlUtil.processXmlElements( + descriptorFile, + processor, + true + ); + } } return new CachedValueProvider.Result<XmlEntityDecl>(result[0], ArrayUtil.toObjectArray(deps)); diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java index 36ae151d5964..5d35f0f4ae69 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java @@ -325,7 +325,11 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum final CachedValue<XmlAttributeDescriptor> value = CachedValuesManager.getManager(includedDocument.getProject()).createCachedValue( new CachedValueProvider<XmlAttributeDescriptor>(){ public Result<XmlAttributeDescriptor> compute() { - return new Result<XmlAttributeDescriptor>(attributeDescriptor, attributeDescriptor.getDependences()); + Object[] deps = attributeDescriptor.getDependences(); + if (deps.length == 0) { + LOG.error(attributeDescriptor + " returned no dependencies"); + } + return new Result<XmlAttributeDescriptor>(attributeDescriptor, deps); } }, false diff --git a/xml/xml-psi-impl/src/com/intellij/xml/index/XmlIndex.java b/xml/xml-psi-impl/src/com/intellij/xml/index/XmlIndex.java index 1e549442011a..fb5242cb3e51 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/index/XmlIndex.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/index/XmlIndex.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. @@ -95,13 +95,15 @@ public abstract class XmlIndex<V> extends FileBasedIndexExtension<String, V> { }; } + @NotNull public KeyDescriptor<String> getKeyDescriptor() { return KEY_DESCRIPTOR; } + @NotNull public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(XmlFileType.INSTANCE, DTDFileType.INSTANCE) { - public boolean acceptInput(final VirtualFile file) { + public boolean acceptInput(@NotNull final VirtualFile file) { FileType fileType = file.getFileType(); final String extension = file.getExtension(); return XmlFileType.INSTANCE.equals(fileType) && "xsd".equals(extension) || diff --git a/xml/xml-psi-impl/src/com/intellij/xml/index/XmlNamespaceIndex.java b/xml/xml-psi-impl/src/com/intellij/xml/index/XmlNamespaceIndex.java index 55cde705430c..923a5cfce4e0 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/index/XmlNamespaceIndex.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/index/XmlNamespaceIndex.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. @@ -107,11 +107,12 @@ public class XmlNamespaceIndex extends XmlIndex<XsdNamespaceBuilder> { }; } + @NotNull @Override public DataExternalizer<XsdNamespaceBuilder> getValueExternalizer() { return new DataExternalizer<XsdNamespaceBuilder>() { @Override - public void save(DataOutput out, XsdNamespaceBuilder value) throws IOException { + public void save(@NotNull DataOutput out, XsdNamespaceBuilder value) throws IOException { out.writeUTF(value.getNamespace() == null ? "" : value.getNamespace()); out.writeUTF(value.getVersion() == null ? "" : value.getVersion()); out.writeInt(value.getTags().size()); @@ -121,7 +122,7 @@ public class XmlNamespaceIndex extends XmlIndex<XsdNamespaceBuilder> { } @Override - public XsdNamespaceBuilder read(DataInput in) throws IOException { + public XsdNamespaceBuilder read(@NotNull DataInput in) throws IOException { int count; XsdNamespaceBuilder builder = new XsdNamespaceBuilder(in.readUTF(), in.readUTF(), new ArrayList<String>(count = in.readInt())); |