diff --git a/java/compiler/impl/compiler-impl.iml b/java/compiler/impl/compiler-impl.iml
index 4f7473c9ff2a..a65d7e10171d 100644
--- a/java/compiler/impl/compiler-impl.iml
+++ b/java/compiler/impl/compiler-impl.iml
@@ -31,6 +31,7 @@
+
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerCacheManager.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerCacheManager.java
index 4afce35c12ac..b93583556588 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerCacheManager.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerCacheManager.java
@@ -44,7 +44,7 @@ import java.util.Map;
public class CompilerCacheManager implements ProjectComponent {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.CompilerCacheManager");
private final Map myCompilerToCacheMap = new HashMap();
- private final Map, NewCompilerCache,?>> myNewCachesMap = new HashMap, NewCompilerCache,?>>();
+ private final Map, NewCompilerCache,?,?>> myNewCachesMap = new HashMap, NewCompilerCache,?,?>>();
private final List myCacheDisposables = new ArrayList();
private final File myCachesRoot;
private final Runnable myShutdownTask = new Runnable() {
@@ -90,10 +90,11 @@ public class CompilerCacheManager implements ProjectComponent {
return dir;
}
- public synchronized NewCompilerCache getNewCompilerCache(NewCompiler compiler) throws IOException {
- NewCompilerCache, ?> cache = myNewCachesMap.get(compiler);
+ public synchronized NewCompilerCache
+ getNewCompilerCache(NewCompiler compiler) throws IOException {
+ NewCompilerCache,?,?> cache = myNewCachesMap.get(compiler);
if (cache == null) {
- final NewCompilerCache, ?> newCache = new NewCompilerCache(compiler, NewCompilerRunner.getNewCompilerCacheDir(myProject, compiler));
+ final NewCompilerCache,?,?> newCache = new NewCompilerCache(compiler, NewCompilerRunner.getNewCompilerCacheDir(myProject, compiler));
myNewCachesMap.put(compiler, newCache);
myCacheDisposables.add(new Disposable() {
@Override
@@ -104,7 +105,7 @@ public class CompilerCacheManager implements ProjectComponent {
cache = newCache;
}
//noinspection unchecked
- return (NewCompilerCache)cache;
+ return (NewCompilerCache)cache;
}
public synchronized FileProcessingCompilerStateCache getFileProcessingCompilerCache(FileProcessingCompiler compiler) throws IOException {
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/NewCompilerRunner.java b/java/compiler/impl/src/com/intellij/compiler/impl/NewCompilerRunner.java
index a5dc5e2ffc24..1b7e3438d5ea 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/NewCompilerRunner.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/NewCompilerRunner.java
@@ -15,14 +15,17 @@
*/
package com.intellij.compiler.impl;
+import com.google.common.base.Throwables;
import com.intellij.compiler.impl.newApi.*;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ReadAction;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.RunResult;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
@@ -43,7 +46,7 @@ public class NewCompilerRunner {
private CompileContext myContext;
private final boolean myForceCompile;
private final boolean myOnlyCheckStatus;
- private final NewCompiler,?>[] myCompilers;
+ private final NewCompiler,?,?>[] myCompilers;
private final Project myProject;
public NewCompilerRunner(CompileContext context, CompilerManager compilerManager, boolean forceCompile, boolean onlyCheckStatus) {
@@ -57,7 +60,7 @@ public class NewCompilerRunner {
public boolean invokeCompilers(NewCompiler.CompileOrderPlace place) throws CompileDriver.ExitException {
boolean didSomething = false;
try {
- for (NewCompiler, ?> compiler : myCompilers) {
+ for (NewCompiler,?,?> compiler : myCompilers) {
if (compiler.getOrderPlace().equals(place)) {
didSomething = invokeCompiler(compiler);
}
@@ -81,13 +84,13 @@ public class NewCompilerRunner {
return didSomething;
}
- private boolean invokeCompiler(NewCompiler compiler) throws IOException, CompileDriver.ExitException {
+ private boolean invokeCompiler(NewCompiler compiler) throws IOException, CompileDriver.ExitException {
return invokeCompiler(compiler, compiler.createInstance(myContext));
}
- private , Key, State>
- boolean invokeCompiler(NewCompiler compiler, CompilerInstance instance) throws IOException, CompileDriver.ExitException {
- NewCompilerCache cache = CompilerCacheManager.getInstance(myProject).getNewCompilerCache(compiler);
+ private , Key, SourceState, OutputState>
+ boolean invokeCompiler(NewCompiler compiler, CompilerInstance instance) throws IOException, CompileDriver.ExitException {
+ NewCompilerCache cache = CompilerCacheManager.getInstance(myProject).getNewCompilerCache(compiler);
NewCompilerPersistentData data = new NewCompilerPersistentData(getNewCompilerCacheDir(myProject, compiler), compiler.getVersion());
if (data.isVersionChanged()) {
LOG.info("Clearing cache for " + compiler.getDescription());
@@ -106,10 +109,10 @@ public class NewCompilerRunner {
}
List keys = new ArrayList();
cache.processSources(id, new CommonProcessors.CollectProcessor(keys));
- List> obsoleteSources = new ArrayList>();
+ List> obsoleteSources = new ArrayList>();
for (Key key : keys) {
- final State state = cache.getState(id, key);
- obsoleteSources.add(Pair.create(key, state));
+ final NewCompilerCache.PersistentStateData state = cache.getState(id, key);
+ obsoleteSources.add(new NewCompilerItemState(key, state.mySourceState, state.myOutputState));
}
instance.processObsoleteTarget(target, obsoleteSources);
if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
@@ -131,23 +134,24 @@ public class NewCompilerRunner {
return didSomething;
}
- public static File getNewCompilerCacheDir(Project project, NewCompiler, ?> compiler) {
+ public static File getNewCompilerCacheDir(Project project, NewCompiler,?,?> compiler) {
return new File(CompilerPaths.getCacheStoreDirectory(project), compiler.getId());
}
- private , Key, State>
- boolean processTarget(T target, final int targetId, final NewCompiler compiler, final CompilerInstance instance,
- final NewCompilerCache cache) throws IOException, CompileDriver.ExitException {
+ private , Key, SourceState, OutputState>
+ boolean processTarget(T target, final int targetId, final NewCompiler compiler, final CompilerInstance instance,
+ final NewCompilerCache cache) throws IOException, CompileDriver.ExitException {
if (LOG.isDebugEnabled()) {
LOG.debug("Processing target '" + target + "' (id=" + targetId + ")");
}
final List- items = instance.getItems(target);
if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) return true;
- final List> toProcess = new ArrayList>();
+ final List> toProcess = new ArrayList>();
final THashSet keySet = new THashSet(new SourceItemHashingStrategy(compiler));
final Ref exception = Ref.create(null);
DumbService.getInstance(myProject).waitForSmartMode();
+ final Map
- sourceStates = new HashMap
- ();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
@@ -155,9 +159,13 @@ public class NewCompilerRunner {
for (Item item : items) {
final Key key = item.getKey();
keySet.add(key);
- State output = cache.getState(targetId, key);
- if (myForceCompile || output == null || !item.isUpToDate(output)) {
- toProcess.add(Pair.create(item, output));
+ final NewCompilerCache.PersistentStateData data = cache.getState(targetId, key);
+ SourceState sourceState = data != null ? data.mySourceState : null;
+ final OutputState outputState = data != null ? data.myOutputState : null;
+ if (myForceCompile || sourceState == null || !item.isSourceUpToDate(sourceState)
+ || outputState == null || !item.isOutputUpToDate(outputState)) {
+ sourceStates.put(item, item.computeSourceState());
+ toProcess.add(new NewCompilerItemState
- (item, sourceState, outputState));
}
}
}
@@ -193,9 +201,10 @@ public class NewCompilerRunner {
throw new CompileDriver.ExitException(CompileDriver.ExitStatus.CANCELLED);
}
- List> obsoleteItems = new ArrayList>();
+ List> obsoleteItems = new ArrayList>();
for (Key key : toRemove) {
- obsoleteItems.add(Pair.create(key, cache.getState(targetId, key)));
+ final NewCompilerCache.PersistentStateData data = cache.getState(targetId, key);
+ obsoleteItems.add(new NewCompilerItemState(key, data.mySourceState, data.myOutputState));
}
final List
- processedItems = new ArrayList
- ();
@@ -218,9 +227,19 @@ public class NewCompilerRunner {
cache.remove(targetId, key);
}
CompilerUtil.refreshIOFiles(toRefresh);
- for (Item item : processedItems) {
- cache.putOutput(targetId, item.getKey(), item.computeState());
- }
+
+ final RunResult runResult = new ReadAction() {
+ protected void run(final Result result) throws Throwable {
+ for (Item item : processedItems) {
+ SourceState sourceState = sourceStates.get(item);
+ if (sourceState == null) {
+ sourceState = item.computeSourceState();
+ }
+ cache.putState(targetId, item.getKey(), sourceState, item.computeOutputState());
+ }
+ }
+ }.executeSilently();
+ Throwables.propagateIfPossible(runResult.getThrowable(), IOException.class);
return true;
@@ -229,7 +248,7 @@ public class NewCompilerRunner {
private class SourceItemHashingStrategy
implements TObjectHashingStrategy {
private KeyDescriptor myKeyDescriptor;
- public SourceItemHashingStrategy(NewCompiler compiler) {
+ public SourceItemHashingStrategy(NewCompiler compiler) {
myKeyDescriptor = compiler.getItemKeyDescriptor();
}
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompileItem.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompileItem.java
index fb941ca3e4b2..df5eb2fbfc14 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompileItem.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompileItem.java
@@ -20,12 +20,18 @@ import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
-public abstract class CompileItem {
+public abstract class CompileItem {
@NotNull
public abstract Key getKey();
- public abstract boolean isUpToDate(@NotNull State state);
+ public abstract boolean isSourceUpToDate(@NotNull SourceState state);
@NotNull
- public abstract State computeState();
+ public abstract SourceState computeSourceState();
+
+
+ public abstract boolean isOutputUpToDate(@NotNull OutputState state);
+
+ @NotNull
+ public abstract OutputState computeOutputState();
}
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompilerInstance.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompilerInstance.java
index 2e9f9cf59593..f5a9df2d41f0 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompilerInstance.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompilerInstance.java
@@ -17,7 +17,6 @@ package com.intellij.compiler.impl.newApi;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import java.io.File;
@@ -26,7 +25,7 @@ import java.util.List;
/**
* @author nik
*/
-public abstract class CompilerInstance, Key, State> {
+public abstract class CompilerInstance, Key, SourceState, OutputState> {
protected final CompileContext myContext;
protected CompilerInstance(CompileContext context) {
@@ -43,16 +42,16 @@ public abstract class CompilerInstance getSelectedTargets();
- public abstract void processObsoleteTarget(@NotNull String targetId, @NotNull List> obsoleteItems);
+ public abstract void processObsoleteTarget(@NotNull String targetId, @NotNull List> obsoleteItems);
@NotNull
public abstract List- getItems(@NotNull T target);
- public abstract void processItems(@NotNull T target, @NotNull List> changedItems, @NotNull List> obsoleteItems,
+ public abstract void processItems(@NotNull T target, @NotNull List> changedItems, @NotNull List> obsoleteItems,
@NotNull OutputConsumer
- consumer);
- public interface OutputConsumer
- > {
+ public interface OutputConsumer
- > {
void addFileToRefresh(@NotNull File file);
void addProcessedItem(@NotNull Item sourceItem);
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompiler.java
index b82b8bf9d84c..11c770a62461 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompiler.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompiler.java
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
-public abstract class NewCompiler implements Compiler {
+public abstract class NewCompiler implements Compiler {
private final String myId;
private final int myVersion;
private final CompileOrderPlace myOrderPlace;
@@ -38,10 +38,12 @@ public abstract class NewCompiler implements Compiler {
@NotNull
public abstract KeyDescriptor getItemKeyDescriptor();
@NotNull
- public abstract DataExternalizer getItemStateExternalizer();
+ public abstract DataExternalizer getSourceStateExternalizer();
+ @NotNull
+ public abstract DataExternalizer getOutputStateExternalizer();
@NotNull
- public abstract CompilerInstance, ? extends CompileItem, Key, State> createInstance(@NotNull CompileContext context);
+ public abstract CompilerInstance, ? extends CompileItem, Key, SourceState, OutputState> createInstance(@NotNull CompileContext context);
public final String getId() {
return myId;
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerCache.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerCache.java
index 0b6ea2ecc3e0..6982e084a52b 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerCache.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerCache.java
@@ -17,6 +17,7 @@ package com.intellij.compiler.impl.newApi;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.Processor;
+import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentHashMap;
@@ -28,28 +29,25 @@ import java.io.IOException;
/**
* @author nik
*/
-public class NewCompilerCache {
+public class NewCompilerCache {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.newApi.NewCompilerCache");
- private PersistentHashMap, State> myPersistentMap;
+ private PersistentHashMap, PersistentStateData> myPersistentMap;
private File myCacheFile;
- private final NewCompiler myCompiler;
+ private final NewCompiler myCompiler;
- public NewCompilerCache(NewCompiler compiler, final File compilerCacheDir) throws IOException {
+ public NewCompilerCache(NewCompiler compiler, final File compilerCacheDir) throws IOException {
myCompiler = compiler;
myCacheFile = new File(compilerCacheDir, "timestamps");
createMap();
}
private void createMap() throws IOException {
- myPersistentMap = new PersistentHashMap, State>(myCacheFile, new SourceItemDataDescriptor(myCompiler.getItemKeyDescriptor()),
- myCompiler.getItemStateExternalizer());
+ myPersistentMap = new PersistentHashMap, PersistentStateData>(myCacheFile, new SourceItemDataDescriptor(myCompiler.getItemKeyDescriptor()),
+ new PersistentStateDataExternalizer(myCompiler));
}
private KeyAndTargetData getKeyAndTargetData(Key key, int target) {
- KeyAndTargetData data = new KeyAndTargetData();
- data.myTarget = target;
- data.myKey = key;
- return data;
+ return new KeyAndTargetData(target, key);
}
public void wipe() throws IOException {
@@ -75,7 +73,7 @@ public class NewCompilerCache {
myPersistentMap.remove(getKeyAndTargetData(key, targetId));
}
- public State getState(int targetId, Key key) throws IOException {
+ public PersistentStateData getState(int targetId, Key key) throws IOException {
return myPersistentMap.get(getKeyAndTargetData(key, targetId));
}
@@ -88,16 +86,31 @@ public class NewCompilerCache {
});
}
- public void putOutput(int targetId, Key key, State outputItem) throws IOException {
- myPersistentMap.put(getKeyAndTargetData(key, targetId), outputItem);
+ public void putState(int targetId, Key key, SourceState sourceState, OutputState outputState) throws IOException {
+ myPersistentMap.put(getKeyAndTargetData(key, targetId), new PersistentStateData(sourceState, outputState));
}
private static class KeyAndTargetData {
- public int myTarget;
- public Key myKey;
+ public final int myTarget;
+ public final Key myKey;
+
+ private KeyAndTargetData(int target, Key key) {
+ myTarget = target;
+ myKey = key;
+ }
}
+ public static class PersistentStateData {
+ public final SourceState mySourceState;
+ public final OutputState myOutputState;
+
+ private PersistentStateData(SourceState sourceState, OutputState outputState) {
+ mySourceState = sourceState;
+ myOutputState = outputState;
+ }
+ }
+
private class SourceItemDataDescriptor implements KeyDescriptor> {
private final KeyDescriptor myKeyDescriptor;
@@ -129,4 +142,27 @@ public class NewCompilerCache {
return getKeyAndTargetData(item, target);
}
}
+
+ private class PersistentStateDataExternalizer implements DataExternalizer> {
+ private DataExternalizer mySourceStateExternalizer;
+ private DataExternalizer myOutputStateExternalizer;
+
+ public PersistentStateDataExternalizer(NewCompiler compiler) {
+ mySourceStateExternalizer = compiler.getSourceStateExternalizer();
+ myOutputStateExternalizer = compiler.getOutputStateExternalizer();
+ }
+
+ @Override
+ public void save(DataOutput out, PersistentStateData value) throws IOException {
+ mySourceStateExternalizer.save(out, value.mySourceState);
+ myOutputStateExternalizer.save(out, value.myOutputState);
+ }
+
+ @Override
+ public PersistentStateData read(DataInput in) throws IOException {
+ SourceState sourceState = mySourceStateExternalizer.read(in);
+ OutputState outputState = myOutputStateExternalizer.read(in);
+ return new PersistentStateData(sourceState, outputState);
+ }
+ }
}
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerItemState.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerItemState.java
new file mode 100644
index 000000000000..4dd7084fec76
--- /dev/null
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerItemState.java
@@ -0,0 +1,43 @@
+/*
+ * 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.compiler.impl.newApi;
+
+/**
+ * @author nik
+ */
+public class NewCompilerItemState
- {
+ private final Item myItem;
+ private final SourceState mySourceState;
+ private final OutputState myOutputState;
+
+ public NewCompilerItemState(Item item, SourceState sourceState, OutputState outputState) {
+ myItem = item;
+ mySourceState = sourceState;
+ myOutputState = outputState;
+ }
+
+ public Item getItem() {
+ return myItem;
+ }
+
+ public SourceState getSourceState() {
+ return mySourceState;
+ }
+
+ public OutputState getOutputState() {
+ return myOutputState;
+ }
+}
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerPersistentData.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerPersistentData.java
index 1746c334cf77..703a206c7d1f 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerPersistentData.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerPersistentData.java
@@ -30,7 +30,7 @@ import java.util.Set;
*/
public class NewCompilerPersistentData {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.newApi.NewCompilerPersistentData");
- private static final int VERSION = 0;
+ private static final int VERSION = 1;
private File myFile;
private Map myTarget2Id = new HashMap();
private TIntHashSet myUsedIds = new TIntHashSet();
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/SingleTargetCompilerInstance.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/SingleTargetCompilerInstance.java
index 359366e70bb4..4e5b5fb51dd6 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/SingleTargetCompilerInstance.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/SingleTargetCompilerInstance.java
@@ -16,7 +16,6 @@
package com.intellij.compiler.impl.newApi;
import com.intellij.openapi.compiler.CompileContext;
-import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
@@ -25,7 +24,7 @@ import java.util.List;
/**
* @author nik
*/
-public abstract class SingleTargetCompilerInstance
- , S, O> extends CompilerInstance {
+public abstract class SingleTargetCompilerInstance
- , K,S, O> extends CompilerInstance {
protected SingleTargetCompilerInstance(CompileContext context) {
super(context);
}
@@ -43,6 +42,6 @@ public abstract class SingleTargetCompilerInstance
-
}
@Override
- public void processObsoleteTarget(@NotNull String targetId, @NotNull List> obsoleteItems) {
+ public void processObsoleteTarget(@NotNull String targetId, @NotNull List> obsoleteItems) {
}
}
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileCompileItem.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileCompileItem.java
index a2c0b7055c9f..9131318960e6 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileCompileItem.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileCompileItem.java
@@ -23,7 +23,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
-public abstract class VirtualFileCompileItem extends CompileItem {
+public abstract class VirtualFileCompileItem extends CompileItem {
public static final KeyDescriptor KEY_DESCRIPTOR = new EnumeratorStringDescriptor();
protected final VirtualFile myFile;
@@ -36,15 +36,16 @@ public abstract class VirtualFileCompileItem implements DataExternalizer {
- protected abstract void doSave(DataOutput out, State value) throws IOException;
-
- protected abstract State doRead(DataInput in, long sourceTimestamp) throws IOException;
+public class VirtualFileStateExternalizer implements DataExternalizer {
+ public static VirtualFileStateExternalizer INSTANCE = new VirtualFileStateExternalizer();
@Override
- public final void save(DataOutput out, State value) throws IOException {
+ public void save(DataOutput out, VirtualFilePersistentState value) throws IOException {
out.writeLong(value.getSourceTimestamp());
- doSave(out, value);
}
@Override
- public final State read(DataInput in) throws IOException {
- final long sourceTimestamp = in.readLong();
- return doRead(in, sourceTimestamp);
+ public VirtualFilePersistentState read(DataInput in) throws IOException {
+ return new VirtualFilePersistentState(in.readLong());
}
}
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactCompilerCompileItem.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactCompilerCompileItem.java
index 517bef7e89d3..05113499af2a 100644
--- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactCompilerCompileItem.java
+++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactCompilerCompileItem.java
@@ -46,7 +46,7 @@ public class ArtifactCompilerCompileItem extends VirtualFileCompileItem> pairs = new SmartList>();
for (DestinationInfo destination : myDestinations) {
destination.update();
@@ -54,11 +54,11 @@ public class ArtifactCompilerCompileItem extends VirtualFileCompileItem> cachedDestinations = state.myDestinations;
if (cachedDestinations.size() != myDestinations.size()) {
return false;
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 f1adc4c406e1..030e9484ba26 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
@@ -15,9 +15,9 @@
*/
package com.intellij.packaging.impl.compiler;
-import com.intellij.compiler.impl.newApi.VirtualFileStateExternalizer;
import com.intellij.openapi.util.Pair;
import com.intellij.util.SmartList;
+import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.IOUtil;
import java.io.DataInput;
@@ -27,12 +27,11 @@ import java.io.IOException;
/**
* @author nik
*/
-public class ArtifactPackagingItemExternalizer
- extends VirtualFileStateExternalizer {
+public class ArtifactPackagingItemExternalizer implements DataExternalizer {
private byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer();
@Override
- protected void doSave(DataOutput out, ArtifactPackagingItemOutputState value) throws IOException {
+ public void save(DataOutput out, ArtifactPackagingItemOutputState value) throws IOException {
out.writeInt(value.myDestinations.size());
for (Pair pair : value.myDestinations) {
IOUtil.writeUTFFast(myBuffer, out, pair.getFirst());
@@ -41,7 +40,7 @@ public class ArtifactPackagingItemExternalizer
}
@Override
- protected ArtifactPackagingItemOutputState doRead(DataInput in, long sourceTimestamp) throws IOException {
+ public ArtifactPackagingItemOutputState read(DataInput in) throws IOException {
int size = in.readInt();
SmartList> destinations = new SmartList>();
while (size-- > 0) {
@@ -49,6 +48,6 @@ public class ArtifactPackagingItemExternalizer
long outputTimestamp = in.readLong();
destinations.add(Pair.create(path, outputTimestamp));
}
- return new ArtifactPackagingItemOutputState(sourceTimestamp, destinations);
+ return new ArtifactPackagingItemOutputState(destinations);
}
}
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemOutputState.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemOutputState.java
index e93390d6bc72..29ac0ae91918 100644
--- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemOutputState.java
+++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemOutputState.java
@@ -15,18 +15,16 @@
*/
package com.intellij.packaging.impl.compiler;
-import com.intellij.compiler.impl.newApi.VirtualFilePersistentState;
import com.intellij.openapi.util.Pair;
import com.intellij.util.SmartList;
/**
* @author nik
*/
-public class ArtifactPackagingItemOutputState extends VirtualFilePersistentState {
+public class ArtifactPackagingItemOutputState {
public final SmartList> myDestinations;
- public ArtifactPackagingItemOutputState(long timestamp, SmartList> destinations) {
- super(timestamp);
+ public ArtifactPackagingItemOutputState(SmartList> destinations) {
myDestinations = destinations;
}
}
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompiler.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompiler.java
index b410fe456a78..b8cdb63fdb6b 100644
--- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompiler.java
+++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompiler.java
@@ -15,10 +15,7 @@
*/
package com.intellij.packaging.impl.compiler;
-import com.intellij.compiler.impl.newApi.CompileItem;
-import com.intellij.compiler.impl.newApi.CompilerInstance;
-import com.intellij.compiler.impl.newApi.NewCompiler;
-import com.intellij.compiler.impl.newApi.VirtualFileCompileItem;
+import com.intellij.compiler.impl.newApi.*;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerManager;
@@ -35,7 +32,7 @@ import java.util.Set;
/**
* @author nik
*/
-public class ArtifactsCompiler extends NewCompiler {
+public class ArtifactsCompiler extends NewCompiler {
static final Key> WRITTEN_PATHS_KEY = Key.create("artifacts_written_paths");
static final Key> AFFECTED_ARTIFACTS = Key.create("affected_artifacts");
@@ -57,13 +54,19 @@ public class ArtifactsCompiler extends NewCompiler getItemStateExternalizer() {
- return ArtifactCompilerCompileItem.OUTPUT_EXTERNALIZER;
+ public DataExternalizer getSourceStateExternalizer() {
+ return VirtualFileStateExternalizer.INSTANCE;
}
@NotNull
@Override
- public CompilerInstance, String, ArtifactPackagingItemOutputState> createInstance(
+ public DataExternalizer getOutputStateExternalizer() {
+ return new ArtifactPackagingItemExternalizer();
+ }
+
+ @NotNull
+ @Override
+ public CompilerInstance, String, VirtualFilePersistentState, ArtifactPackagingItemOutputState> createInstance(
@NotNull CompileContext context) {
return new ArtifactsCompilerInstance(context);
}
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java
index 46c1ed0bab25..5f995f90048b 100644
--- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java
+++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java
@@ -18,6 +18,8 @@ package com.intellij.packaging.impl.compiler;
import com.intellij.compiler.CompilerManagerImpl;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.newApi.CompilerInstance;
+import com.intellij.compiler.impl.newApi.NewCompilerItemState;
+import com.intellij.compiler.impl.newApi.VirtualFilePersistentState;
import com.intellij.compiler.impl.packagingCompiler.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
@@ -31,7 +33,7 @@ import com.intellij.openapi.deployment.DeploymentUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
-import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
@@ -60,7 +62,7 @@ import java.util.*;
* @author nik
*/
public class ArtifactsCompilerInstance extends CompilerInstance {
+ String, VirtualFilePersistentState, ArtifactPackagingItemOutputState> {
private static final Logger LOG = Logger.getInstance("#com.intellij.packaging.impl.compiler.ArtifactsCompilerInstance");
private ArtifactsProcessingItemsBuilderContext myBuilderContext;
@@ -117,8 +119,9 @@ public class ArtifactsCompilerInstance extends CompilerInstance> obsoleteItems) {
- deleteFiles(obsoleteItems, Collections.>emptyList());
+ public void processObsoleteTarget(@NotNull String targetId,
+ @NotNull List> obsoleteItems) {
+ deleteFiles(obsoleteItems, Collections.>emptyList());
}
@NotNull
@@ -160,7 +163,7 @@ public class ArtifactsCompilerInstance extends CompilerInstance> changedItems,
+ private boolean doBuild(final List> changedItems,
final Set processedItems,
final @NotNull Set writtenPaths, final Set deletedJars) {
final boolean testMode = ApplicationManager.getApplication().isUnitTestMode();
@@ -179,8 +182,8 @@ public class ArtifactsCompilerInstance extends CompilerInstance item : changedItems) {
- final ArtifactCompilerCompileItem sourceItem = item.getFirst();
+ for (final NewCompilerItemState item : changedItems) {
+ final ArtifactCompilerCompileItem sourceItem = item.getItem();
myContext.getProgressIndicator().checkCanceled();
final Ref exception = Ref.create(null);
@@ -304,9 +307,10 @@ public class ArtifactsCompilerInstance extends CompilerInstance> changedItems,
- @NotNull List> obsoleteItems,
- @NotNull final OutputConsumer consumer) {
+ public void processItems(@NotNull ArtifactBuildTarget target,
+ @NotNull final List> changedItems,
+ @NotNull List> obsoleteItems,
+ @NotNull OutputConsumer consumer) {
final THashSet deletedJars = deleteFiles(obsoleteItems, changedItems);
@@ -333,8 +337,8 @@ public class ArtifactsCompilerInstance extends CompilerInstance deleteFiles(List> obsoleteItems,
- List> changedItems) {
+ private THashSet deleteFiles(List> obsoleteItems,
+ List> changedItems) {
myContext.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.deleting.outdated.files"));
final boolean testMode = ApplicationManager.getApplication().isUnitTestMode();
@@ -345,21 +349,21 @@ public class ArtifactsCompilerInstance extends CompilerInstance pathToDelete = new THashSet();
- for (Pair item : changedItems) {
- final ArtifactPackagingItemOutputState cached = item.getSecond();
+ for (NewCompilerItemState item : changedItems) {
+ final ArtifactPackagingItemOutputState cached = item.getOutputState();
if (cached != null) {
for (Pair destination : cached.myDestinations) {
pathToDelete.add(destination.getFirst());
}
}
}
- for (Pair item : changedItems) {
- for (DestinationInfo destination : item.getFirst().getDestinations()) {
+ for (NewCompilerItemState item : changedItems) {
+ for (DestinationInfo destination : item.getItem().getDestinations()) {
pathToDelete.remove(destination.getOutputPath());
}
}
- for (Pair item : obsoleteItems) {
- for (Pair destination : item.getSecond().myDestinations) {
+ for (NewCompilerItemState item : obsoleteItems) {
+ for (Pair destination : item.getOutputState().myDestinations) {
pathToDelete.add(destination.getFirst());
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java
index ee1ad874ee3e..38e71b754c3a 100644
--- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java
+++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java
@@ -366,7 +366,7 @@ public class JavaDocUtil {
String s = fixupMatcher.group(1);
//[db] that's workaround to avoid internal bug
- if (!s.equals("\\")) {
+ if (!s.equals("\\") && !secondSymbols.contains(s)) {
secondSymbols.addFirst(s);
}
}
diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java
index e92b5e4830b6..cf68a02fa6e4 100644
--- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java
+++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java
@@ -31,11 +31,14 @@ import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.jsp.jspJava.JspxImportStatement;
import com.intellij.psi.impl.source.resolve.ResolveClassUtil;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReference;
+import com.intellij.psi.impl.source.tree.ElementType;
+import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.jsp.JspFile;
import com.intellij.psi.jsp.JspSpiUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
@@ -59,8 +62,14 @@ public class ImportHelper{
}
public PsiImportList prepareOptimizeImportsResult(@NotNull final PsiJavaFile file) {
+ // Java parser works in a way that comments may be included to the import list, e.g.:
+ // import a;
+ // /* comment */
+ // import b;
+ // We want to preserve those comments then.
+ List comments = new ArrayList();
// Note: this array may contain ".*" for unresolved imports!
- List> names = new ArrayList>(collectNamesToImport(file));
+ List> names = new ArrayList>(collectNamesToImport(file, comments));
Collections.sort(names, new Comparator>() {
public int compare(Pair o1, Pair o2) {
return o1.getFirst().compareTo(o2.getFirst());
@@ -131,15 +140,29 @@ public class ImportHelper{
try {
StringBuilder text = buildImportListText(resultList, classesOrPackagesToImportOnDemand, classesToUseSingle);
+ for (String comment : comments) {
+ text.append("\n").append(comment);
+ }
String ext = StdFileTypes.JAVA.getDefaultExtension();
PsiFileFactory factory = PsiFileFactory.getInstance(file.getProject());
final PsiJavaFile dummyFile = (PsiJavaFile)factory.createFileFromText("_Dummy_." + ext, StdFileTypes.JAVA, text);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(file.getProject());
codeStyleManager.reformat(dummyFile);
- PsiImportList result = dummyFile.getImportList();
+ PsiImportList newImportList = dummyFile.getImportList();
+ PsiImportList result = (PsiImportList)newImportList.copy();
PsiImportList oldList = file.getImportList();
if (oldList.isReplaceEquivalent(result)) return null;
+ PsiElement firstPrevious = newImportList.getPrevSibling();
+ while (firstPrevious != null && firstPrevious.getPrevSibling() != null) {
+ firstPrevious = firstPrevious.getPrevSibling();
+ }
+ for (PsiElement element = firstPrevious; element != null && element != newImportList; element = element.getNextSibling()) {
+ result.add(element.copy());
+ }
+ for (PsiElement element = newImportList.getNextSibling(); element != null; element = element.getNextSibling()) {
+ result.add(element.copy());
+ }
return result;
}
catch(IncorrectOperationException e) {
@@ -603,17 +626,17 @@ public class ImportHelper{
@NotNull
// returns list of (name, isImportStatic) pairs
- private static Collection> collectNamesToImport(@NotNull PsiJavaFile file){
+ private static Collection> collectNamesToImport(@NotNull PsiJavaFile file, List comments){
Set> names = new THashSet>();
final JspFile jspFile = JspPsiUtil.getJspFile(file);
- collectNamesToImport(names, file, jspFile);
+ collectNamesToImport(names, comments, file, jspFile);
if (jspFile != null) {
PsiFile[] files = ArrayUtil.mergeArrays(JspSpiUtil.getIncludingFiles(jspFile), JspSpiUtil.getIncludedFiles(jspFile), PsiFile.class);
for (PsiFile includingFile : files) {
final PsiFile javaRoot = includingFile.getViewProvider().getPsi(StdLanguages.JAVA);
if (javaRoot instanceof PsiJavaFile && file != javaRoot) {
- collectNamesToImport(names, (PsiJavaFile)javaRoot, jspFile);
+ collectNamesToImport(names, comments, (PsiJavaFile)javaRoot, jspFile);
}
}
}
@@ -624,17 +647,19 @@ public class ImportHelper{
}
private static void collectNamesToImport(@NotNull final Set> names,
+ @NotNull List comments,
@NotNull final PsiJavaFile file,
PsiFile context) {
String packageName = file.getPackageName();
final PsiElement[] roots = file.getPsiRoots();
for (PsiElement root : roots) {
- addNamesToImport(names, root, packageName, context);
+ addNamesToImport(names, comments, root, packageName, context);
}
}
private static void addNamesToImport(@NotNull Set> names,
+ @NotNull List comments,
@NotNull PsiElement scope,
@NotNull String thisPackageName,
PsiFile context){
@@ -644,7 +669,15 @@ public class ImportHelper{
stack.add(scope);
while (!stack.isEmpty()) {
final PsiElement child = stack.removeFirst();
- if (child instanceof PsiImportList) continue;
+ if (child instanceof PsiImportList) {
+ for (PsiElement element : child.getChildren()) {
+ IElementType elementType = element.getNode().getElementType();
+ if (!JavaElementType.IMPORT_STATEMENT.equals(elementType) && !ElementType.WHITE_SPACE_BIT_SET.contains(elementType)) {
+ comments.add(element.getText());
+ }
+ }
+ continue;
+ }
if (child instanceof PsiLiteralExpression) continue;
ContainerUtil.addAll(stack, child.getChildren());
diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java
index 84931bc09cad..c00498228edb 100644
--- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java
+++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java
@@ -38,7 +38,6 @@ import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.containers.HashSet;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NonNls;
@@ -589,7 +588,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
String[] names = getSuggestionsByName(propertyName, variableKind, false);
final PsiExpression qualifierExpression = methodExpr.getQualifierExpression();
if (qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() instanceof PsiVariable) {
- names = ArrayUtil.append(names, changeIfNotIdentifier(qualifierExpression.getText() + StringUtil.capitalize(propertyName)));
+ names = ArrayUtil.append(names, StringUtil.sanitizeJavaIdentifier(changeIfNotIdentifier(qualifierExpression.getText() + StringUtil.capitalize(propertyName))));
}
return new NamesByExprInfo(propertyName, names);
}
@@ -945,7 +944,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
@NotNull
public SuggestedNameInfo suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo, PsiElement place, boolean lookForward) {
final String[] names = baseNameInfo.names;
- Set uniqueNames = new HashSet(names.length);
+ final LinkedHashSet uniqueNames = new LinkedHashSet(names.length);
for (String name : names) {
uniqueNames.add(suggestUniqueVariableName(name, place, lookForward));
}
diff --git a/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java b/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java
index 3a495b7816be..041c22e308bc 100644
--- a/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java
+++ b/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java
@@ -36,6 +36,7 @@ public class OptimizeImportsRefactoringHelper implements RefactoringHelper prepareOperation(final UsageInfo[] usages) {
Set javaFiles = new HashSet();
for (UsageInfo usage : usages) {
+ if (usage.isNonCodeUsage) continue;
final PsiElement element = usage.getElement();
if (element != null) {
final PsiFile file = element.getContainingFile();
diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java
index ba351f2a8455..c46c15c4dda5 100644
--- a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java
+++ b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java
@@ -400,7 +400,7 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
return RefactoringUtil.getTypeByExpressionWithExpectedType(expr);
}
- public PsiClass getParentClass(PsiExpression initializerExpression) {
+ public PsiClass getParentClass(@NotNull PsiExpression initializerExpression) {
PsiElement element = initializerExpression.getUserData(ElementToWorkOn.PARENT);
if (element == null) element = initializerExpression.getParent();
PsiElement parent = element;
diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java
index 8c9a56f658f1..5ffe1cdb733f 100644
--- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java
+++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java
@@ -71,7 +71,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
PsiLocalVariable local,
PsiExpression[] occurences,
boolean isStatic) {
- return IntroduceConstantHandler.this.showRefactoringDialog(project, editor, aClass, local.getInitializer(), local.getType(), occurences, null, null);
+ return IntroduceConstantHandler.this.showRefactoringDialog(project, editor, aClass, local.getInitializer(), local.getType(), occurences, local, null);
}
};
return localToFieldHandler.convertLocalToField(localVariable, editor);
@@ -86,6 +86,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
PsiExpression[] occurences,
PsiElement anchorElement,
PsiElement anchorElementIfAll) {
+ final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expr != null ? expr : anchorElement, PsiMethod.class);
for (PsiExpression occurrence : occurences) {
if (RefactoringUtil.isAssignmentLHS(occurrence)) {
String message =
@@ -133,7 +134,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
final IntroduceConstantDialog dialog =
new IntroduceConstantDialog(project, parentClass, expr, localVariable, false, occurences, getParentClass(),
- new TypeSelectorManagerImpl(project, type, expr, occurences));
+ new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurences));
dialog.show();
if (!dialog.isOK()) {
if (occurences.length > 1) {
@@ -161,7 +162,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
@Nullable
private PsiElement isStaticFinalInitializer(PsiExpression expr) {
- PsiClass parentClass = getParentClass(expr);
+ PsiClass parentClass = expr != null ? getParentClass(expr) : null;
if (parentClass == null) return null;
IsStaticFinalInitializerExpression visitor = new IsStaticFinalInitializerExpression(parentClass, expr);
expr.accept(visitor);
@@ -212,7 +213,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
}
}
- public PsiClass getParentClass(PsiExpression initializerExpression) {
+ public PsiClass getParentClass(@NotNull PsiExpression initializerExpression) {
final PsiType type = initializerExpression.getType();
if (type != null && PsiUtil.isConstantExpression(initializerExpression)) {
diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java
index 69f89f7678b0..2be3c0b00098 100644
--- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java
+++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java
@@ -20,7 +20,6 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
-import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.HelpID;
@@ -28,7 +27,6 @@ import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.occurences.*;
-import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
public class IntroduceFieldHandler extends BaseExpressionToFieldHandler {
@@ -96,13 +94,12 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler {
final boolean currentMethodConstructor = containingMethod != null && containingMethod.isConstructor();
final boolean allowInitInMethod = (!currentMethodConstructor || !isInSuperOrThis) && anchorElement instanceof PsiStatement;
final boolean allowInitInMethodIfAll = (!currentMethodConstructor || !isInSuperOrThis) && anchorElementIfAll instanceof PsiStatement;
- type = checkIfTypeAccessible(type, project, parentClass, containingMethod);
IntroduceFieldDialog dialog = new IntroduceFieldDialog(
project, parentClass, expr, localVariable,
currentMethodConstructor,
false, declareStatic, occurencesNumber,
allowInitInMethod, allowInitInMethodIfAll,
- new TypeSelectorManagerImpl(project, type, expr, occurences)
+ new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurences)
);
dialog.show();
@@ -125,23 +122,6 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler {
dialog.getFieldType(), localVariable != null, (TargetDestination)null, false, false);
}
- private static PsiType checkIfTypeAccessible(PsiType type, Project project, PsiClass parentClass, PsiMethod containingMethod) {
- final PsiClass typeClass = PsiUtil.resolveClassInType(type);
- if (typeClass != null) {
- if (typeClass instanceof PsiTypeParameter) {
- if (ArrayUtil.find(parentClass.getTypeParameters(), typeClass) == -1) { //unknown type parameter
- type = PsiType.getJavaLangObject(PsiManager.getInstance(project), GlobalSearchScope.allScope(project));
- }
- } else if (PsiTreeUtil.isAncestor(containingMethod, typeClass, true)) { //local class type
- final PsiClassType[] superTypes = typeClass.getSuperTypes();
- if (superTypes.length > 0) {
- return checkIfTypeAccessible(superTypes[0], project, parentClass, containingMethod);
- }
- }
- }
- return type;
- }
-
private static boolean isInSuperOrThis(PsiExpression occurence) {
return !NotInSuperCallOccurenceFilter.INSTANCE.isOK(occurence) || !NotInThisCallFilter.INSTANCE.isOK(occurence);
}
diff --git a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java
index 7450a36c249b..839f9180ed29 100644
--- a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java
+++ b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java
@@ -21,11 +21,14 @@ import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.codeInsight.TailType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.statistics.StatisticsInfo;
import com.intellij.psi.statistics.StatisticsManager;
+import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.util.RefactoringHierarchyUtil;
+import com.intellij.util.ArrayUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
@@ -35,7 +38,7 @@ import java.util.*;
* @author dsl
*/
public class TypeSelectorManagerImpl implements TypeSelectorManager {
- private final PsiType myDefaultType;
+ private PsiType myDefaultType;
private final PsiExpression myMainOccurence;
private final PsiExpression[] myOccurrences;
private final PsiType[] myTypesForMain;
@@ -47,27 +50,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
private ExpectedTypesProvider myExpectedTypesProvider;
public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression mainOccurence, PsiExpression[] occurrences) {
- myFactory = JavaPsiFacade.getInstance(project).getElementFactory();
- myDefaultType = type;
- myMainOccurence = mainOccurence;
- myOccurrences = occurrences;
- myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project);
-
- myOccurrenceClassProvider = createOccurrenceClassProvider();
- myTypesForMain = getTypesForMain();
- myTypesForAll = getTypesForAll(true);
-
- myIsOneSuggestion =
- myTypesForMain.length == 1 && myTypesForAll.length == 1 &&
- myTypesForAll[0].equals(myTypesForMain[0]);
- if (myIsOneSuggestion) {
- myTypeSelector = new TypeSelector(myTypesForAll[0]);
- }
- else {
- myTypeSelector = new TypeSelector();
- }
-
-
+ this(project, type, null, mainOccurence, occurrences);
}
public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression[] occurrences) {
@@ -94,10 +77,64 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
}
}
+ public TypeSelectorManagerImpl(Project project,
+ PsiType type,
+ PsiMethod containingMethod,
+ PsiExpression mainOccurence,
+ PsiExpression[] occurrences) {
+ myFactory = JavaPsiFacade.getInstance(project).getElementFactory();
+ myDefaultType = type;
+ myMainOccurence = mainOccurence;
+ myOccurrences = occurrences;
+ myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project);
+
+ myOccurrenceClassProvider = createOccurrenceClassProvider();
+ myTypesForMain = getTypesForMain();
+ myTypesForAll = getTypesForAll(true);
+
+ if (containingMethod != null) {
+ if (PsiUtil.resolveClassInType(type) != null) {
+ myDefaultType = checkIfTypeAccessible(type, project, containingMethod);
+ }
+ }
+
+ myIsOneSuggestion =
+ myTypesForMain.length == 1 && myTypesForAll.length == 1 &&
+ myTypesForAll[0].equals(myTypesForMain[0]);
+ if (myIsOneSuggestion) {
+ myTypeSelector = new TypeSelector(myTypesForAll[0]);
+ }
+ else {
+ myTypeSelector = new TypeSelector();
+ }
+ }
+
+ private PsiType checkIfTypeAccessible(PsiType type, Project project, PsiMethod containingMethod) {
+ PsiClass parentClass = containingMethod.getContainingClass();
+ final PsiClass typeClass = PsiUtil.resolveClassInType(type);
+ if (typeClass != null) {
+ if (typeClass instanceof PsiTypeParameter) {
+ if (ArrayUtil.find(parentClass.getTypeParameters(), typeClass) == -1) { //unknown type parameter
+ return PsiType.getJavaLangObject(PsiManager.getInstance(project), GlobalSearchScope.allScope(project));
+ }
+ } else if (PsiTreeUtil.isAncestor(containingMethod, typeClass, true)) { //local class type
+ final int nextTypeIdx = ArrayUtil.find(myTypesForAll, type) + 1;
+ if (nextTypeIdx < myTypesForAll.length) {
+ return checkIfTypeAccessible(myTypesForAll[nextTypeIdx], project, containingMethod);
+ }
+ }
+ }
+ return type;
+ }
+
public PsiType[] getTypesForAll() {
return myTypesForAll;
}
+ public PsiType getDefaultType() {
+ return myDefaultType;
+ }
+
private ExpectedTypesProvider.ExpectedClassProvider createOccurrenceClassProvider() {
final Set occurrenceClasses = new HashSet();
for (final PsiExpression occurence : myOccurrences) {
diff --git a/java/java-impl/src/com/intellij/testIntegration/JavaTestCreator.java b/java/java-impl/src/com/intellij/testIntegration/JavaTestCreator.java
index 3edb3d5bdc5c..d85ac9212f16 100644
--- a/java/java-impl/src/com/intellij/testIntegration/JavaTestCreator.java
+++ b/java/java-impl/src/com/intellij/testIntegration/JavaTestCreator.java
@@ -15,14 +15,26 @@
*/
package com.intellij.testIntegration;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
import com.intellij.testIntegration.createTest.CreateTestAction;
import com.intellij.util.IncorrectOperationException;
public class JavaTestCreator implements TestCreator {
+ private static final Logger LOG = Logger.getInstance("com.intellij.testIntegration.JavaTestCreator");
+
+
+ @Override
+ public boolean isAvailable(Project project, Editor editor, PsiFile file) {
+ CreateTestAction action = new CreateTestAction();
+ PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
+
+ return action.isAvailableForElement(element);
+ }
+
public void createTest(Project project, Editor editor, PsiFile file) {
try {
CreateTestAction action = new CreateTestAction();
@@ -32,7 +44,7 @@ public class JavaTestCreator implements TestCreator {
}
}
catch (IncorrectOperationException e) {
- throw new RuntimeException(e);
+ LOG.warn(e);
}
}
}
diff --git a/java/java-tests/testData/refactoring/introduceConstant/ResultedType.java b/java/java-tests/testData/refactoring/introduceConstant/ResultedType.java
new file mode 100644
index 000000000000..e29702a58f1a
--- /dev/null
+++ b/java/java-tests/testData/refactoring/introduceConstant/ResultedType.java
@@ -0,0 +1,6 @@
+class Test {
+ void foo() {
+ class C {}
+ C cc;
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/introduceConstant/ResultedTypeWhenNonLocal.java b/java/java-tests/testData/refactoring/introduceConstant/ResultedTypeWhenNonLocal.java
new file mode 100644
index 000000000000..8b36707e23c5
--- /dev/null
+++ b/java/java-tests/testData/refactoring/introduceConstant/ResultedTypeWhenNonLocal.java
@@ -0,0 +1,7 @@
+class Test {
+ class C {}
+
+ void foo() {
+ C cc;
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceConstantTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceConstantTest.java
index de321991b063..1afa4324a13f 100644
--- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceConstantTest.java
+++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceConstantTest.java
@@ -1,12 +1,13 @@
package com.intellij.refactoring;
import com.intellij.JavaTestUtil;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiJavaFile;
-import com.intellij.psi.PsiLocalVariable;
+import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import com.intellij.testFramework.LightCodeInsightTestCase;
import com.intellij.testFramework.TestDataPath;
import com.intellij.util.VisibilityUtil;
@@ -87,6 +88,37 @@ public class IntroduceConstantTest extends LightCodeInsightTestCase {
checkResultByFile(BASE_PATH + getTestName(false) + "_after.java");
}
+ public void testResultedType() throws Exception {
+ checkDefaultType("java.lang.Object");
+ }
+
+ public void testResultedTypeWhenNonLocal() throws Exception {
+ checkDefaultType("Test.C");
+ }
+
+ private void checkDefaultType(final String expectedType) throws Exception {
+ configureByFile(BASE_PATH + getTestName(false) + ".java");
+ new MockIntroduceConstantHandler(null){
+ @Override
+ protected Settings showRefactoringDialog(Project project,
+ Editor editor,
+ PsiClass parentClass,
+ PsiExpression expr,
+ PsiType type,
+ PsiExpression[] occurences,
+ PsiElement anchorElement,
+ PsiElement anchorElementIfAll) {
+ final TypeSelectorManagerImpl selectorManager =
+ new TypeSelectorManagerImpl(project, type, PsiTreeUtil.getParentOfType(anchorElement, PsiMethod.class), expr, occurences);
+ final PsiType psiType = selectorManager.getDefaultType();
+ Assert.assertEquals(psiType.getCanonicalText(), expectedType);
+ return new Settings("xxx", true, true, true,
+ InitializationPlace.IN_FIELD_DECLARATION, getVisibility(), null, psiType, false,
+ parentClass, false, false);
+ }
+ }.invoke(getProject(), getEditor(), getFile(), null);
+ }
+
protected Sdk getProjectJDK() {
return JavaSdkImpl.getMockJdk17("java 1.5");
}
diff --git a/java/openapi/src/com/intellij/openapi/roots/libraries/JarVersionDetectionUtil.java b/java/openapi/src/com/intellij/openapi/roots/libraries/JarVersionDetectionUtil.java
index 646745128338..efbd4fe49bd4 100644
--- a/java/openapi/src/com/intellij/openapi/roots/libraries/JarVersionDetectionUtil.java
+++ b/java/openapi/src/com/intellij/openapi/roots/libraries/JarVersionDetectionUtil.java
@@ -43,10 +43,19 @@ public class JarVersionDetectionUtil {
@Nullable
public static String detectJarVersion(@NotNull final String detectionClass, @NotNull Module module) {
try {
- final ZipFile zipFile = getDetectionJar(detectionClass, module);
- if (zipFile == null) {
- return null;
- }
+ return detectJarVersion(getDetectionJar(detectionClass, module));
+ }
+ catch (IOException e) {
+ return null;
+ }
+ }
+
+ @Nullable
+ public static String detectJarVersion(ZipFile zipFile) {
+ if (zipFile == null) {
+ return null;
+ }
+ try {
final ZipEntry zipEntry = zipFile.getEntry(JarFile.MANIFEST_NAME);
if (zipEntry == null) {
return null;
diff --git a/platform/lang-api/src/com/intellij/testIntegration/TestCreator.java b/platform/lang-api/src/com/intellij/testIntegration/TestCreator.java
index bb426123e500..8cb85c1ed3aa 100644
--- a/platform/lang-api/src/com/intellij/testIntegration/TestCreator.java
+++ b/platform/lang-api/src/com/intellij/testIntegration/TestCreator.java
@@ -21,5 +21,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
public interface TestCreator {
+ boolean isAvailable(Project project, Editor editor, PsiFile file);
void createTest(Project project, Editor editor, PsiFile file);
}
diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/AutomaticRenamingDialog.java b/platform/lang-impl/src/com/intellij/refactoring/rename/AutomaticRenamingDialog.java
index 01b15258e6e6..bf851a55e397 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/rename/AutomaticRenamingDialog.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/rename/AutomaticRenamingDialog.java
@@ -16,15 +16,12 @@
package com.intellij.refactoring.rename;
-import com.intellij.navigation.ItemPresentation;
-import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiNamedElement;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.rename.naming.AutomaticRenamer;
@@ -250,7 +247,7 @@ public class AutomaticRenamingDialog extends DialogWrapper {
case CHECK_COLUMN:
return Boolean.valueOf(myShouldRename[rowIndex]);
case OLD_NAME_COLUMN:
- return "" + RefactoringUIUtil.getDescription(myRenames[rowIndex], true) + "";
+ return "" + RefactoringUIUtil.getDescription(myRenames[rowIndex], true) + "";
case NEW_NAME_COLUMN:
return myNewNames[rowIndex];
default:
diff --git a/platform/lang-impl/src/com/intellij/testIntegration/GotoTestOrCodeHandler.java b/platform/lang-impl/src/com/intellij/testIntegration/GotoTestOrCodeHandler.java
index 285a1b33ebe2..48900b1271c5 100644
--- a/platform/lang-impl/src/com/intellij/testIntegration/GotoTestOrCodeHandler.java
+++ b/platform/lang-impl/src/com/intellij/testIntegration/GotoTestOrCodeHandler.java
@@ -53,23 +53,25 @@ public class GotoTestOrCodeHandler extends GotoTargetHandler {
}
else {
candidates = TestFinderHelper.findTestsForClass(selectedElement);
- actions.add(new AdditionalAction() {
- @Override
- public String getText() {
- return "Create New Test...";
- }
+ final TestCreator creator = LanguageTestCreators.INSTANCE.forLanguage(file.getLanguage());
+ if (creator != null && creator.isAvailable(file.getProject(), editor, file)) {
+ actions.add(new AdditionalAction() {
+ @Override
+ public String getText() {
+ return "Create New Test...";
+ }
- @Override
- public Icon getIcon() {
- return IconLoader.getIcon("/actions/intentionBulb.png");
- }
+ @Override
+ public Icon getIcon() {
+ return IconLoader.getIcon("/actions/intentionBulb.png");
+ }
- @Override
- public void execute() {
- final TestCreator creator = LanguageTestCreators.INSTANCE.forLanguage(file.getLanguage());
- if (creator != null) creator.createTest(file.getProject(), editor, file);
- }
- });
+ @Override
+ public void execute() {
+ creator.createTest(file.getProject(), editor, file);
+ }
+ });
+ }
}
return new GotoData(sourceElement, candidates.toArray(new PsiElement[candidates.size()]), actions);
diff --git a/platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java b/platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java
index 22eaa410843b..b57f180933c3 100644
--- a/platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java
+++ b/platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java
@@ -65,7 +65,7 @@ public interface TextAnnotationGutterProvider {
/***
* enables annotation view modifications
*/
- List getPopupActions(final Editor editor);
+ List getPopupActions(final int line, final Editor editor);
/**
* Called when the annotations are removed from the editor gutter.
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 951cf17efc0e..ddc7397ec43b 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
@@ -1191,8 +1191,12 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
DefaultActionGroup actionGroup = new DefaultActionGroup(EditorBundle.message("editor.annotations.action.group.name"), true);
actionGroup.add(new CloseAnnotationsAction());
final List addActions = new ArrayList();
+ final Point p = e.getPoint();
+ int line = myEditor.xyToLogicalPosition(new Point(0, (int)p.getY())).line;
+ if (line >= myEditor.getDocument().getLineCount()) return;
+
for (TextAnnotationGutterProvider gutterProvider : myTextAnnotationGutters) {
- final List list = gutterProvider.getPopupActions(myEditor);
+ final List list = gutterProvider.getPopupActions(line, myEditor);
if (list != null) {
for (AnAction action : list) {
if (! addActions.contains(action)) {
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 5c2448d6ec1d..663ac91f62ad 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
@@ -59,7 +59,6 @@ import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.GuiUtils;
-import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.LightweightHint;
import com.intellij.ui.components.JBScrollBar;
import com.intellij.ui.components.JBScrollPane;
@@ -72,6 +71,7 @@ import com.intellij.util.ui.EmptyClipboardOwner;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.update.UiNotifyConnector;
import gnu.trove.TIntArrayList;
+import gnu.trove.TIntHashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -1203,12 +1203,18 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myGutterComponent.repaint(0, yStartLine, myGutterComponent.getWidth(), yEndLine - yStartLine);
}
+ /**
+ * Asks to repaint all logical lines from the given
[start; end] range.
+ *
+ * @param startLine start logical line to repaint (inclusive)
+ * @param endLine end logical line to repaint (inclusive)
+ */
public void repaintLines(int startLine, int endLine) {
if (!isShowing()) return;
Rectangle visibleArea = getScrollingModel().getVisibleArea();
int yStartLine = logicalLineToY(startLine);
- int yEndLine = logicalLineToY(endLine) + getLineHeight() + WAVE_HEIGHT;
+ int yEndLine = logicalPositionToXY(new LogicalPosition(endLine + 1, 0)).y + WAVE_HEIGHT;
myEditorComponent.repaintEditorComponent(visibleArea.x, yStartLine, visibleArea.x + visibleArea.width, yEndLine - yStartLine);
myGutterComponent.repaint(0, yStartLine, myGutterComponent.getWidth(), yEndLine - yStartLine);
@@ -1578,20 +1584,31 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int visibleLineNumber = clip.y / lineHeight;
- int startLineNumber = xyToLogicalPosition(new Point(0, clip.y)).line;
+ VisualPosition visualPosition = xyToVisualPosition(new Point(0, clip.y));
+ LogicalPosition logicalPosition = visualToLogicalPosition(visualPosition);
Point position = new Point(0, visibleLineNumber * lineHeight);
- if (startLineNumber == 0 && myPrefixText != null) {
+ if (visualPosition.line == 0 && myPrefixText != null) {
position.x = drawBackground(g, myPrefixAttributes.getBackgroundColor(), new String(myPrefixText), position, myPrefixAttributes.getFontType(),
defaultBackground, clip);
}
- if (startLineNumber >= myDocument.getLineCount() || startLineNumber < 0) {
+ if (logicalPosition.line >= myDocument.getLineCount() || logicalPosition.line < 0) {
if (position.x > 0) flushBackground(g, clip);
return;
}
- int start = myDocument.getLineStartOffset(startLineNumber);
+ int start = logicalPositionToOffset(logicalPosition);
+
+ // There is a possible case that we need to draw background from the start of soft wrap-introduced visual line. Given position
+ // has valid 'y' coordinate then at it shouldn't be affected by soft wrap that corresponds to the visual line start offset.
+ // Hence, we store information about soft wrap to be skipped for further processing and adjust 'x' coordinate value if necessary.
+ TIntHashSet softWrapsToSkip = new TIntHashSet();
+ TextChange softWrap = getSoftWrapModel().getSoftWrap(start);
+ if (softWrap != null) {
+ position.x = getSoftWrapModel().getSoftWrapIndentWidthInPixels(softWrap);
+ softWrapsToSkip.add(softWrap.getStart());
+ }
IterationState iterationState = new IterationState(this, start, paintSelection());
@@ -1620,7 +1637,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start);
if (collapsedFolderAt == null) {
position.x = drawSoftWrapAwareBackground(g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType,
- defaultBackground, clip);
+ defaultBackground, clip, softWrapsToSkip);
if (lIterator.getLineNumber() < lastLineIndex) {
if (backColor != null && !backColor.equals(defaultBackground)) {
@@ -1653,11 +1670,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
if (hEnd > lEnd - lIterator.getSeparatorLength()) {
position.x = drawSoftWrapAwareBackground(
g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType,
- defaultBackground, clip
+ defaultBackground, clip, softWrapsToSkip
);
}
else {
- position.x = drawSoftWrapAwareBackground(g, backColor, text, start, hEnd, position, fontType, defaultBackground, clip);
+ position.x = drawSoftWrapAwareBackground(
+ g, backColor, text, start, hEnd, position, fontType, defaultBackground, clip, softWrapsToSkip
+ );
}
}
@@ -1716,12 +1735,15 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
private int drawSoftWrapAwareBackground(Graphics g, Color backColor, CharSequence text, int start, int end, Point position,
- int fontType, Color defaultBackground, Rectangle clip)
+ int fontType, Color defaultBackground, Rectangle clip, TIntHashSet processSoftWrap)
{
int startToUse = start;
List extends TextChange> softWraps = getSoftWrapModel().getSoftWrapsForRange(start, end);
for (TextChange softWrap : softWraps) {
int softWrapStart = softWrap.getStart();
+ if (processSoftWrap.contains(softWrapStart)) {
+ continue;
+ }
if (startToUse < softWrapStart) {
position.x = drawBackground(g, backColor, text.subSequence(startToUse, softWrapStart), position, fontType, defaultBackground, clip);
}
@@ -1739,7 +1761,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int fontType, Color defaultBackground, Rectangle clip)
{
position.x = drawBackground(
- g, backColor, getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED), position, fontType,
+ g, backColor, getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED), position,
defaultBackground, clip
);
@@ -1763,7 +1785,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
position.x = drawBackground(
- g, backColor, getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP), position, fontType,
+ g, backColor, getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP), position,
defaultBackground, clip
);
}
@@ -1772,14 +1794,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
Rectangle clip)
{
int width = getTextSegmentWidth(text, position.x, fontType, clip);
- return drawBackground(g, backColor, width, position, fontType, defaultBackground, clip);
+ return drawBackground(g, backColor, width, position, defaultBackground, clip);
}
private int drawBackground(Graphics g,
Color backColor,
int width,
Point position,
- int fontType,
Color defaultBackground,
Rectangle clip) {
if (backColor != null && !backColor.equals(defaultBackground) && clip.intersects(position.x, position.y, width, getLineHeight())) {
@@ -3400,7 +3421,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myCommandProcessor.executeCommand(myProject, new DocumentRunnable(myDocument, myProject) {
public void run() {
int oldSelectionStart = mySelectionModel.getLeadSelectionOffset();
- LogicalPosition caretPosition = getCaretModel().getLogicalPosition();
+ VisualPosition caretPosition = getCaretModel().getVisualPosition();
int columnNumber = caretPosition.column;
xPassedCycles++;
if (xPassedCycles >= myXCycles) {
@@ -3415,8 +3436,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
lineNumber += myDy;
}
- LogicalPosition pos = new LogicalPosition(lineNumber, columnNumber);
- getCaretModel().moveToLogicalPosition(pos);
+ VisualPosition pos = new VisualPosition(lineNumber, columnNumber);
+ getCaretModel().moveToVisualPosition(pos);
getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
int newCaretOffset = getCaretModel().getOffset();
@@ -4886,13 +4907,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
int maxWidth = 0;
for (int i = startToUse; i < endToUse; i++) {
- // TODO den unwrap
- try {
- maxWidth = Math.max(maxWidth, myLineWidths.getQuick(i));
- }
- catch (Exception e) {
- e.printStackTrace();
- }
+ maxWidth = Math.max(maxWidth, myLineWidths.getQuick(i));
}
mySize = new Dimension(maxWidth, getLineHeight() * getVisibleLineCount());
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java
index 0acc7f978cb4..72e1d096fab7 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java
@@ -21,7 +21,6 @@
package com.intellij.execution.testframework;
import com.intellij.execution.Location;
-import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
@@ -91,4 +90,30 @@ public abstract class AbstractTestProxy extends CompositePrintable {
Disposer.dispose(proxy);
}
}
+
+ public static void flushOutput(AbstractTestProxy testProxy) {
+ testProxy.flush();
+
+ AbstractTestProxy parent = testProxy.getParent();
+ while (parent != null) {
+ final List extends AbstractTestProxy> children = parent.getChildren();
+ if (!testProxy.isInProgress() && testProxy.equals(children.get(children.size() - 1))) {
+ parent.flush();
+ } else {
+ break;
+ }
+ testProxy = parent;
+ parent = parent.getParent();
+ }
+ }
+
+ @Override
+ public int getExceptionMark() {
+ if (myExceptionMark == 0 && getChildren().size() > 0) {
+ return getChildren().get(0).getExceptionMark();
+ }
+ return myExceptionMark;
+ }
+
+
}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java b/platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java
index 18035b78ff2d..a37168ced4a4 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java
@@ -15,42 +15,211 @@
*/
package com.intellij.execution.testframework;
+import com.intellij.execution.filters.HyperlinkInfo;
+import com.intellij.execution.testframework.stacktrace.DiffHyperlink;
+import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.Disposable;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.io.IOUtil;
+import org.jetbrains.annotations.NonNls;
+import java.io.*;
import java.util.ArrayList;
-
import java.util.List;
public class CompositePrintable implements Printable, Disposable {
public static final String NEW_LINE = "\n";
- protected final ArrayList myNestedPrintables = new ArrayList();
+ protected final List myNestedPrintables = new ArrayList();
+ private PrintablesWrapper myWrapper;
+ protected int myExceptionMark;
+
+ public void flush() {
+ if (myWrapper == null) {
+ try {
+ myWrapper = new PrintablesWrapper(File.createTempFile("frst", "scd"));
+ }
+ catch (IOException ignored) {
+ }
+ }
+ if (myWrapper != null) {
+ synchronized (myNestedPrintables) {
+ myWrapper.flash(myNestedPrintables);
+ clear();
+ }
+ }
+ }
public void printOn(final Printer printer) {
- printAllOn(myNestedPrintables, printer);
+ if (myWrapper != null) {
+ myWrapper.printOn(printer);
+ }
+ synchronized (myNestedPrintables) {
+ for (int i = 0; i < myNestedPrintables.size(); i++) {
+ if (i == getExceptionMark() && i > 0) printer.mark();
+ myNestedPrintables.get(i).printOn(printer);
+ }
+ }
}
public void addLast(final Printable printable) {
- myNestedPrintables.add(printable);
+ synchronized (myNestedPrintables) {
+ myNestedPrintables.add(printable);
+ }
}
protected void clear() {
- myNestedPrintables.clear();
+ synchronized (myNestedPrintables) {
+ myNestedPrintables.clear();
+ }
}
public int getCurrentSize() {
return myNestedPrintables.size();
}
- public static void printAllOn(final List printables, final Printer console) {
- for (final T printable : printables) {
- printable.printOn(console);
- }
- }
-
@Override
public void dispose() {
clear();
+ if (myWrapper != null) {
+ myWrapper.dispose();
+ }
+ }
+
+ public int getExceptionMark() {
+ return myExceptionMark;
+ }
+
+ public void setExceptionMark(int exceptionMark) {
+ myExceptionMark = exceptionMark;
+ }
+
+ private static final Logger LOG = Logger.getInstance("#" + PrintablesWrapper.class.getName());
+
+ private class PrintablesWrapper {
+
+ @NonNls private static final String HYPERLINK = "hyperlink";
+ private DataInputStream myReader;
+ private ConsoleViewContentType myLastSelected;
+ private final File myFile;
+
+ PrintablesWrapper(File file) {
+ myFile = file;
+ }
+
+ public void flash(List printables) {
+ final DataOutputStream fileWriter;
+ try {
+ fileWriter = new DataOutputStream(new FileOutputStream(myFile, true));
+
+ }
+ catch (FileNotFoundException e) {
+ LOG.error(e);
+ return;
+ }
+ try {
+ for (final Printable printable : printables) {
+ printable.printOn(new Printer() {
+ @Override
+ public void print(String text, ConsoleViewContentType contentType) {
+ try {
+ IOUtil.writeString(contentType.toString() + text, fileWriter);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ @Override
+ public void onNewAvailable(Printable printable11) {
+ }
+
+ @Override
+ public void printHyperlink(String text, HyperlinkInfo info) {
+ if (info instanceof DiffHyperlink.DiffHyperlinkInfo) {
+ final DiffHyperlink diffHyperlink = ((DiffHyperlink.DiffHyperlinkInfo)info).getPrintable();
+ try {
+ IOUtil.writeString(HYPERLINK, fileWriter);
+ IOUtil.writeString(diffHyperlink.getLeft(), fileWriter);
+ IOUtil.writeString(diffHyperlink.getRight(), fileWriter);
+ IOUtil.writeString(diffHyperlink.getFilePath(), fileWriter);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ else {
+ print(text, ConsoleViewContentType.NORMAL_OUTPUT);
+ }
+ }
+
+ @Override
+ public void mark() {
+ }
+ });
+ }
+ }
+ finally {
+ try {
+ fileWriter.close();
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ }
+
+ public void printOn(Printer console) {
+ try {
+ myReader = new DataInputStream(new FileInputStream(myFile));
+ int lineNum = 0;
+ while (myReader.available() > 0) {
+ if (lineNum == CompositePrintable.this.getExceptionMark() && lineNum > 0) console.mark();
+ final String line = IOUtil.readString(myReader);
+ if (!isApplicable(console, line, ConsoleViewContentType.ERROR_OUTPUT)) {
+ if (!isApplicable(console, line, ConsoleViewContentType.SYSTEM_OUTPUT)) {
+ if (!isApplicable(console, line, ConsoleViewContentType.NORMAL_OUTPUT)) {
+ if (line.startsWith(HYPERLINK)) {
+ new DiffHyperlink(IOUtil.readString(myReader), IOUtil.readString(myReader), IOUtil.readString(myReader)).printOn(console);
+ }
+ else {
+ console.print(line, myLastSelected != null ? myLastSelected : ConsoleViewContentType.NORMAL_OUTPUT);
+ }
+ }
+ }
+ }
+ lineNum++;
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ finally {
+ try {
+ if (myReader != null) {
+ myReader.close();
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ }
+
+ private boolean isApplicable(Printer console, String line, ConsoleViewContentType contentType) {
+ final String prefix = contentType.toString();
+ if (line.startsWith(prefix)) {
+ console.print(line.substring(prefix.length()), contentType);
+ myLastSelected = contentType;
+ return true;
+ }
+ return false;
+ }
+
+ public void dispose() {
+ FileUtil.delete(myFile);
+ }
}
}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java b/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java
index b17c1989947d..b1a01e8dcf5e 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java
@@ -38,11 +38,7 @@ public class DiffHyperlink implements Printable {
protected final String myExpected;
protected final String myActual;
protected final String myFilePath;
- private final HyperlinkInfo myDiffHyperlink = new HyperlinkInfo() {
- public void navigate(final Project project) {
- openDiff(project);
- }
- };
+ private final HyperlinkInfo myDiffHyperlink = new DiffHyperlinkInfo();
public DiffHyperlink(final String expected, final String actual, final String filePath) {
@@ -80,6 +76,10 @@ public class DiffHyperlink implements Printable {
return myActual;
}
+ public String getFilePath() {
+ return myFilePath;
+ }
+
public void printOn(final Printer printer) {
if (hasMoreThanOneLine(myActual) || hasMoreThanOneLine(myExpected)) {
printer.print(" ", ConsoleViewContentType.ERROR_OUTPUT);
@@ -98,4 +98,14 @@ public class DiffHyperlink implements Printable {
private static boolean hasMoreThanOneLine(final String string) {
return string.indexOf('\n') != -1 || string.indexOf('\r') != -1;
}
+
+ public class DiffHyperlinkInfo implements HyperlinkInfo {
+ public void navigate(final Project project) {
+ openDiff(project);
+ }
+
+ public DiffHyperlink getPrintable() {
+ return DiffHyperlink.this;
+ }
+ }
}
\ No newline at end of file
diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
index 24144ebeb38b..b09340a4bf2a 100644
--- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
@@ -31,11 +31,8 @@ import org.jetbrains.annotations.Nullable;
import java.beans.Introspector;
import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
import java.text.DateFormat;
import java.util.*;
-import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -1608,6 +1605,19 @@ public class StringUtil {
return "a" + Character.toUpperCase(c) + name.substring(1);
}
+ public static String sanitizeJavaIdentifier(String name) {
+ final StringBuilder result = new StringBuilder();
+
+ for (int i = 0; i < name.length(); i++) {
+ final char ch = name.charAt(i);
+ if (Character.isLetterOrDigit(ch)) {
+ result.append(ch);
+ }
+ }
+
+ return result.toString();
+ }
+
public static void assertValidSeparators(@NotNull CharSequence s) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '\r') {
diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java b/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java
index 370cf192e1ba..2dc07b928bca 100644
--- a/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java
+++ b/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java
@@ -72,7 +72,7 @@ public abstract class AbstractVcsHelper {
showErrors(Arrays.asList(e), s);
}
- public abstract void showAnnotation(FileAnnotation annotation, VirtualFile file);
+ public abstract void showAnnotation(FileAnnotation annotation, VirtualFile file, AbstractVcs vcs);
public abstract void showDifferences(final VcsFileRevision cvsVersionOn, final VcsFileRevision cvsVersionOn1, final File file);
diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java b/platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java
index eda912583fab..2c4bcc8a9d7f 100644
--- a/platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java
+++ b/platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java
@@ -19,6 +19,7 @@ package com.intellij.openapi.vcs;
import com.intellij.openapi.vcs.changes.committed.DecoratorManager;
import com.intellij.openapi.vcs.changes.committed.VcsCommittedListsZipper;
import com.intellij.openapi.vcs.changes.committed.VcsCommittedViewAuxiliary;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
import com.intellij.openapi.vcs.versionBrowser.ChangesBrowserSettingsEditor;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
@@ -55,4 +56,7 @@ public interface CommittedChangesProvider gutters = new ArrayList();
final AnnotationSourceSwitcher switcher = fileAnnotation.getAnnotationSourceSwitcher();
- final MyAnnotationPresentation presentation = new MyAnnotationPresentation(highlighting, switcher, editorGutterComponentEx, gutters);
+ final MyAnnotationPresentation presentation;
+ if (vcs.getCommittedChangesProvider() != null) {
+ final ShowDiffFromAnnotation showDiff = new ShowDiffFromAnnotation(getUpToDateLineNumber, fileAnnotation, vcs, file);
+ presentation = new MyAnnotationPresentation(highlighting, switcher, editorGutterComponentEx, gutters, showDiff);
+ presentation.addLineNumberListener(showDiff);
+ } else {
+ presentation = new MyAnnotationPresentation(highlighting, switcher, editorGutterComponentEx, gutters);
+ }
if (switcher != null) {
@@ -375,15 +393,25 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
private final List myGutters;
private final List myActions;
private MySwitchAnnotationSourceAction mySwitchAction;
+ private final List> myPopupLineNumberListeners;
public MyAnnotationPresentation(@NotNull final HighlightAnnotationsActions highlighting, @Nullable final AnnotationSourceSwitcher switcher,
- final EditorGutterComponentEx gutter,
- List gutters) {
+ final EditorGutterComponentEx gutter, final List