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, Key, State> createInstance(@NotNull CompileContext context); + public abstract CompilerInstance, 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 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 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 gutters, final AnAction... actions) { myHighlighting = highlighting; mySwitcher = switcher; myGutters = gutters; + myPopupLineNumberListeners = new LinkedList>(); - myActions = new ArrayList(myHighlighting.getList()); + myActions = new ArrayList(); + myActions.add(Separator.getInstance()); + if (actions != null) { + final List actionsList = Arrays.asList(actions); + if (! actionsList.isEmpty()) { + myActions.addAll(actionsList); + myActions.add(new Separator()); + } + } + myActions.addAll(myHighlighting.getList()); if (mySwitcher != null) { mySwitchAction = new MySwitchAnnotationSourceAction(mySwitcher, gutter); myActions.add(mySwitchAction); @@ -391,6 +419,10 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware { myActions.add(new ShowHideColorsAction(myGutters, gutter)); } + public void addLineNumberListener(final Consumer listener) { + myPopupLineNumberListeners.add(listener); + } + public EditorFontType getFontType(final int line) { return myHighlighting.isLineBold(line) ? EditorFontType.BOLD : EditorFontType.PLAIN; } @@ -400,7 +432,10 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware { return mySwitcher.getAnnotationSource(line).getColor(); } - public List getActions() { + public List getActions(int line) { + for (Consumer listener : myPopupLineNumberListeners) { + listener.consume(line); + } return myActions; } @@ -443,4 +478,108 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware { myGutter.revalidateMarkup(); } } + + private static class ShowDiffFromAnnotation extends AnAction implements Consumer { + private final UpToDateLineNumberProvider myLineNumberProvider; + private final FileAnnotation myFileAnnotation; + private final AbstractVcs myVcs; + private final VirtualFile myFile; + private RepositoryLocation myLocationFor; + private int currentLine; + + private ShowDiffFromAnnotation(final UpToDateLineNumberProvider lineNumberProvider, + final FileAnnotation fileAnnotation, final AbstractVcs vcs, final VirtualFile file) { + super(VcsBundle.message("updated.info.tree.show.diff.text"), VcsBundle.message("updated.info.tree.show.diff.text"), IconLoader.getIcon("/actions/diff.png")); + myLineNumberProvider = lineNumberProvider; + myFileAnnotation = fileAnnotation; + myVcs = vcs; + myFile = file; + final CommittedChangesProvider provider = myVcs.getCommittedChangesProvider(); + final VirtualFile root = ProjectLevelVcsManager.getInstance(vcs.getProject()).getVcsRootFor(file); + myLocationFor = provider.getLocationFor(new FilePathImpl(root)); + currentLine = -1; + } + + @Override + public void consume(Integer integer) { + currentLine = integer; + } + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setVisible(getActualLineNumber(e) >= 0); + } + + private int getActualLineNumber(final AnActionEvent e) { + final DataContext dc = e.getDataContext(); + if (currentLine < 0) return -1; + return myLineNumberProvider.getLineNumber(currentLine); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final int actualNumber = getActualLineNumber(e); + if (actualNumber < 0) return; + + final VcsRevisionNumber revisionNumber = myFileAnnotation.getLineRevisionNumber(actualNumber); + if (revisionNumber != null) { + final VcsException[] exc = new VcsException[1]; + final List changes = new LinkedList(); + ProgressManager.getInstance().run(new Task.Backgroundable(myVcs.getProject(), + "Loading revision " + revisionNumber.asString() + " contents", true, BackgroundFromStartOption.getInstance()) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + final CommittedChangesProvider provider = myVcs.getCommittedChangesProvider(); + try { + final CommittedChangeList cl = provider.getOneList(myLocationFor, revisionNumber); + if (cl == null) { + ChangesViewBalloonProblemNotifier.showMe(myVcs.getProject(), "Can not load data for show diff", MessageType.ERROR); + return; + } + changes.addAll(cl.getChanges()); + Collections.sort(changes, ChangesComparator.getInstance()); + } + catch (VcsException e1) { + exc[0] = e1; + } + } + + @Override + public void onSuccess() { + if (exc[0] != null) { + ChangesViewBalloonProblemNotifier.showMe(myVcs.getProject(), "Can not show diff: " + exc[0].getMessage(), MessageType.ERROR); + } else if (! changes.isEmpty()) { + int idx = findSelfInList(changes); + ShowDiffAction.showDiffForChange(changes.toArray(new Change[changes.size()]), idx, myVcs.getProject()); + } + } + }); + } + } + + private int findSelfInList(List changes) { + int idx = -1; + final File ioFile = new File(myFile.getPath()); + for (int i = 0; i < changes.size(); i++) { + final Change change = changes.get(i); + if ((change.getAfterRevision() != null) && (change.getAfterRevision().getFile().getIOFile().equals(ioFile))) { + idx = i; + break; + } + } + if (idx >= 0) return idx; + idx = 0; + // try to use name only + final String name = ioFile.getName(); + for (int i = 0; i < changes.size(); i++) { + final Change change = changes.get(i); + if ((change.getAfterRevision() != null) && (change.getAfterRevision().getFile().getName().equals(name))) { + idx = i; + break; + } + } + + return idx; + } + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java index c54ca5b5f338..9ee9edb5b72c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java @@ -99,8 +99,8 @@ class AnnotationFieldGutter implements ActiveAnnotationGutter { return myPresentation.getColor(line); } - public List getPopupActions(final Editor editor) { - return myPresentation.getActions(); + public List getPopupActions(int line, final Editor editor) { + return myPresentation.getActions(line); } public void gutterClosed() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java index 6cd1cb0092bb..52ce811f0cd7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java @@ -68,8 +68,8 @@ public class AnnotationGutterLineConvertorProxy implements ActiveAnnotationGutte return myDelegate.getBgColor(currentLine, editor); } - public List getPopupActions(Editor editor) { - return myDelegate.getPopupActions(editor); + public List getPopupActions(int line, Editor editor) { + return myDelegate.getPopupActions(line, editor); } public void gutterClosed() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/Annotater.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/Annotater.java deleted file mode 100644 index b4f718fc3cc5..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/Annotater.java +++ /dev/null @@ -1,51 +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.openapi.vcs.annotate; - -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.vcs.VcsBundle; -import com.intellij.openapi.vcs.actions.AnnotateToggleAction; -import com.intellij.openapi.vfs.VirtualFile; - -public class Annotater { - - private final Project myProject; - private final VirtualFile myVirtualFile; - private final FileAnnotation myFileAnnotation; - - public Annotater(FileAnnotation fileAnnotation, Project project, VirtualFile virtualFile) { - myFileAnnotation = fileAnnotation; - myProject = project; - myVirtualFile = virtualFile; - } - - public void showAnnotation() { - OpenFileDescriptor openFileDescriptor = new OpenFileDescriptor(myProject, myVirtualFile); - Editor editor = FileEditorManager.getInstance(myProject).openTextEditor(openFileDescriptor, true); - if (editor == null) { - Messages.showMessageDialog(VcsBundle.message("message.text.cannot.open.editor", myVirtualFile.getPresentableUrl()), - VcsBundle.message("message.title.cannot.open.editor"), Messages.getInformationIcon()); - return; - } - - AnnotateToggleAction.doAnnotate(editor, myProject, myVirtualFile, myFileAnnotation); - } - -} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java index 9c13afd02a31..1fca77641739 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java @@ -18,10 +18,11 @@ package com.intellij.openapi.vcs.annotate; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.colors.EditorFontType; + import java.util.List; public interface TextAnnotationPresentation { EditorFontType getFontType(int line); ColorKey getColor(int line); - List getActions(); + List getActions(int line); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java index fe376e3b16d2..94d4fca858a1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.changes.committed; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsType; import com.intellij.util.NotNullFunction; import org.jetbrains.annotations.NotNull; @@ -29,10 +30,10 @@ public class CommittedChangesVisibilityPredicate implements NotNullFunction myMap; private final Set myEnabledVcs = new HashSet(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java index 7b10a69d83eb..c3d080bac8d0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java @@ -16,9 +16,10 @@ package com.intellij.openapi.vcs.changes.committed; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.CachingCommittedChangesProvider; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsType; import com.intellij.util.NotNullFunction; import org.jetbrains.annotations.NotNull; @@ -30,7 +31,7 @@ public class IncomingChangesVisibilityPredicate implements NotNullFunction myRevisionToVirtualFile = new HashMap(); - public FileHistoryPanelImpl(Project project, - FilePath filePath, final String repositoryPath, VcsHistorySession session, + public FileHistoryPanelImpl(AbstractVcs vcs, + FilePath filePath, VcsHistorySession session, VcsHistoryProvider provider, AnnotationProvider annotationProvider, ContentManager contentManager, final Runnable refresher) { super(contentManager, provider.getHelpId() != null ? provider.getHelpId() : "reference.versionControl.toolwindow.history"); + myVcs = vcs; myProvider = provider; myAnnotationProvider = annotationProvider; - myProject = project; myRefresher = refresher; myHistorySession = session; myFilePath = filePath; - COLUMNS = createColumnList(project, provider, session); + COLUMNS = createColumnList(myVcs.getProject(), provider, session); myComments = new JEditorPane(UIUtil.HTML_MIME, ""); myComments.setPreferredSize(new Dimension(150, 100)); @@ -298,11 +298,11 @@ public class FileHistoryPanelImpl 1) { - showDifferences(myProject, sel.get(0), sel.get(sel.size() - 1)); + showDifferences(myVcs.getProject(), sel.get(0), sel.get(sel.size() - 1)); } else if (selectionSize == 1) { final VcsRevisionNumber currentRevisionNumber = myHistorySession.getCurrentRevisionNumber(); if (currentRevisionNumber != null) { - showDifferences(myProject, getFirstSelectedRevision(), new CurrentRevision(myFilePath.getVirtualFile(), currentRevisionNumber)); + showDifferences(myVcs.getProject(), getFirstSelectedRevision(), new CurrentRevision(myFilePath.getVirtualFile(), currentRevisionNumber)); } } } @@ -880,7 +880,7 @@ public class FileHistoryPanelImpl fileAnnotationRef = new Ref(); final Ref exceptionRef = new Ref(); - ProgressManager.getInstance().run(new Task.Backgroundable(myProject, VcsBundle.message("retrieving.annotations"), true, + ProgressManager.getInstance().run(new Task.Backgroundable(myVcs.getProject(), VcsBundle.message("retrieving.annotations"), true, BackgroundFromStartOption.getInstance()) { public void run(@NotNull ProgressIndicator indicator) { try { @@ -1102,7 +1102,7 @@ public class FileHistoryPanelImpl() { + public void consume(LogInformationWrapper wrapper) { + if (result[0] != null) return; + final List wrappers = builder.revisionWrappersFromLog(wrapper); + if (wrappers != null) { + for (RevisionWrapper revisionWrapper : wrappers) { + if (Comparing.equal(revisionWrapper.getRevision().getNumber(), number.asString())) { + result[0] = builder.addRevision(revisionWrapper); + } + } + } + } + }); + + if (executionResult.isCanceled()) { + throw new ProcessCanceledException(); + } + else if (! executionResult.hasNoErrors()) { + throw executionResult.composeError(); + } + return result[0]; + } + public List getCommittedChanges(ChangeBrowserSettings settings, RepositoryLocation location, final int maxCount) throws VcsException { CvsRepositoryLocation cvsLocation = (CvsRepositoryLocation) location; return loadCommittedChanges(settings, cvsLocation.getModuleName(), cvsLocation.getEnvironment(), cvsLocation.getRootFile()); diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java index 87c4fc0fc076..4e4d95033fad 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java @@ -172,9 +172,10 @@ public class BrowserPanel extends JPanel implements DataProvider, CvsTabbedWindo public void actionPerformed(AnActionEvent e) { VcsVirtualFile vcsVirtualFile = (VcsVirtualFile)getCvsVirtualFile(); try { - final FileAnnotation annotation = CvsVcs2.getInstance(myProject) + final CvsVcs2 vcs = CvsVcs2.getInstance(myProject); + final FileAnnotation annotation = vcs .createAnnotation(vcsVirtualFile, vcsVirtualFile.getRevision(), myCvsRootConfiguration); - AbstractVcsHelper.getInstance(myProject).showAnnotation(annotation, vcsVirtualFile); + AbstractVcsHelper.getInstance(myProject).showAnnotation(annotation, vcsVirtualFile, vcs); } catch (VcsException e1) { AbstractVcsHelper.getInstance(myProject).showError(e1, CvsBundle.message("operation.name.annotate")); diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java index 744f35c474fa..4b6ad47caba7 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java @@ -171,7 +171,7 @@ public class CvsHistoryProvider implements VcsHistoryProvider { @Nullable public VcsRevisionNumber calcCurrentRevisionNumber() { - return getCurrentRevision(myFilePath); + return myFilePath == null ? null : getCurrentRevision(myFilePath); } @Override diff --git a/plugins/git4idea/src/git4idea/GitVcs.java b/plugins/git4idea/src/git4idea/GitVcs.java index 4f69c496b5c5..5e2d107c71f9 100644 --- a/plugins/git4idea/src/git4idea/GitVcs.java +++ b/plugins/git4idea/src/git4idea/GitVcs.java @@ -338,8 +338,7 @@ public class GitVcs extends AbstractVcs { */ @Override public CommittedChangesProvider getCommittedChangesProvider() { - // TODO Temporary disabled: return myCommittedChangeListProvider; - return null; + return myCommittedChangeListProvider; } /** diff --git a/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java b/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java index d8bd592e96d2..569d888a7ffb 100644 --- a/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java +++ b/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java @@ -49,7 +49,7 @@ import java.util.List; /** * The provider for committed change lists */ -public class GitCommittedChangeListProvider implements CachingCommittedChangesProvider { +public class GitCommittedChangeListProvider implements CommittedChangesProvider { /** * the logger */ @@ -224,6 +224,29 @@ public class GitCommittedChangeListProvider implements CachingCommittedChangesPr return -1; } + @Override + public CommittedChangeList getOneList(RepositoryLocation location, final VcsRevisionNumber number) throws VcsException { + final GitRepositoryLocation l = (GitRepositoryLocation)location; + VirtualFile root = LocalFileSystem.getInstance().findFileByIoFile(l.getRoot()); + if (root == null) { + throw new VcsException("The repository does not exists anymore: " + l.getRoot()); + } + + final CommittedChangeList[] result = new CommittedChangeList[1]; + GitUtil.getLocalCommittedChanges(myProject, root, new Consumer() { + public void consume(GitSimpleHandler h) { + h.addParameters("-n1"); + h.addParameters(number.asString()); + } + }, new Consumer() { + @Override + public void consume(CommittedChangeList committedChangeList) { + result[0] = committedChangeList; + } + }, false); + return result[0]; + } + public int getFormatVersion() { return 0; } diff --git a/plugins/git4idea/src/git4idea/history/browser/GitProjectLogManager.java b/plugins/git4idea/src/git4idea/history/browser/GitProjectLogManager.java index eb433b631899..4bfb534bab4c 100644 --- a/plugins/git4idea/src/git4idea/history/browser/GitProjectLogManager.java +++ b/plugins/git4idea/src/git4idea/history/browser/GitProjectLogManager.java @@ -155,20 +155,25 @@ public class GitProjectLogManager { content.setCloseable(false); cvcm.addContent(content); newKeys.put(root, content); - - new CalculateContinuation().calculateAndContinue(new ThrowableComputable() { - public String compute() throws Exception { - return getCaption(baseDir, root); + + new AbstractCalledLater(myProject, ModalityState.NON_MODAL) { + @Override + public void run() { + new CalculateContinuation().calculateAndContinue(new ThrowableComputable() { + public String compute() throws Exception { + return getCaption(baseDir, root); + } + }, new CatchingConsumer() { + public void consume(Exception e) { + //should not + LOG.info(e); + } + public void consume(final String caption) { + content.setDisplayName(caption); + } + }); } - }, new CatchingConsumer() { - public void consume(Exception e) { - //should not - LOG.info(e); - } - public void consume(final String caption) { - content.setDisplayName(caption); - } - }); + }.callMe(); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyImportOptimizerRefactoringHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyImportOptimizerRefactoringHelper.java index dcc7cbf13b46..a88811a33bd8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyImportOptimizerRefactoringHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyImportOptimizerRefactoringHelper.java @@ -44,6 +44,7 @@ public class GroovyImportOptimizerRefactoringHelper implements RefactoringHelper public Set prepareOperation(UsageInfo[] usages) { Set files = 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/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java index e0024efbb318..bad269b1dcaf 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java @@ -268,4 +268,18 @@ public class HgCachingCommitedChangesProvider public int getUnlimitedCountValue() { return -1; } + + @Override + public CommittedChangeList getOneList(RepositoryLocation location, VcsRevisionNumber number) throws VcsException { + final ChangeBrowserSettings settings = createDefaultSettings(); + settings.USE_CHANGE_AFTER_FILTER = true; + settings.USE_CHANGE_BEFORE_FILTER = true; + settings.CHANGE_AFTER = number.asString(); + settings.CHANGE_BEFORE = number.asString(); + final List list = getCommittedChanges(settings, location, 1); + if (list.size() == 1) { + return list.get(0); + } + return null; + } } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index a9232d65affa..0a74c06fdb82 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -265,7 +265,7 @@ public abstract class TestObject implements JavaCommandLine { consoleView.initUI(); consoleView.attachToProcess(handler); unboundOutputRoot.setPrinter(consoleView.getPrinter()); - + Disposer.register(consoleView, unboundOutputRoot); final TestsPacketsReceiver packetsReceiver = new TestsPacketsReceiver(consoleView) { @Override public void notifyStart(TestProxy root) { diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/TestsPacketsReceiver.java b/plugins/junit/src/com/intellij/execution/junit2/ui/TestsPacketsReceiver.java index b6106e55e2b3..7862a1dfc286 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/TestsPacketsReceiver.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/TestsPacketsReceiver.java @@ -232,6 +232,7 @@ public class TestsPacketsReceiver implements PacketProcessor, Disposable { } static void complete(TestProxy testProxy) { + testProxy.flush(); final int magnitude = testProxy.getState().getMagnitude(); TestProxy parent = testProxy.getParent(); @@ -240,8 +241,9 @@ public class TestsPacketsReceiver implements PacketProcessor, Disposable { final List children = parent.getChildren(); final TestState parentState = parent.getState(); LOG.assertTrue(parentState instanceof SuiteState); - if (child.equals(children.get(children.size() - 1))) { + if (!child.isInProgress() && child.equals(children.get(children.size() - 1))) { ((SuiteState)parentState).setRunning(false); + parent.flush(); } ((SuiteState)parentState).updateMagnitude(magnitude); child = parent; diff --git a/plugins/maven/facade-api/src/org/jetbrains/idea/maven/facade/MavenFacadeLogger.java b/plugins/maven/facade-api/src/org/jetbrains/idea/maven/facade/MavenFacadeLogger.java index 563492e56eed..18deb8dce81e 100644 --- a/plugins/maven/facade-api/src/org/jetbrains/idea/maven/facade/MavenFacadeLogger.java +++ b/plugins/maven/facade-api/src/org/jetbrains/idea/maven/facade/MavenFacadeLogger.java @@ -24,4 +24,6 @@ public interface MavenFacadeLogger extends Remote { void warn(Throwable e) throws RemoteException; void error(Throwable e) throws RemoteException; + + void print(String s) throws RemoteException; } diff --git a/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/CustomRepositoryMetadataManager.java b/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/CustomRepositoryMetadataManager.java new file mode 100644 index 000000000000..9bad5d68c162 --- /dev/null +++ b/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/CustomRepositoryMetadataManager.java @@ -0,0 +1,57 @@ +/* + * 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 org.jetbrains.idea.maven.facade.embedder; + +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.metadata.*; +import org.jetbrains.idea.maven.model.MavenId; + +import java.io.File; +import java.util.List; +import java.util.Map; + +public class CustomRepositoryMetadataManager extends DefaultRepositoryMetadataManager { + private Map myProjectIdToFileMap; + + public void customize(Map projectIdToFileMap) { + myProjectIdToFileMap = projectIdToFileMap; + } + + public void reset() { + myProjectIdToFileMap = null; + } + + @Override + public void resolve(RepositoryMetadata metadata, List remoteRepositories, ArtifactRepository localRepository) + throws RepositoryMetadataResolutionException { + super.resolve(metadata, remoteRepositories, localRepository); + + Map map = myProjectIdToFileMap; + if (map == null) return; + + Metadata data = metadata.getMetadata(); + Versioning versioning = data.getVersioning(); + if (versioning == null) { + data.setVersioning(versioning = new Versioning()); + } + + for (MavenId each : map.keySet()) { + if (each.equals(data.getGroupId(), data.getArtifactId())) { + versioning.addVersion(each.getVersion()); + } + } + } +} diff --git a/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/MavenFacadeEmbedderImpl.java b/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/MavenFacadeEmbedderImpl.java index 93d1ef49386e..cce776af4095 100644 --- a/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/MavenFacadeEmbedderImpl.java +++ b/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/MavenFacadeEmbedderImpl.java @@ -24,8 +24,10 @@ import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.InvalidRepositoryException; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.manager.WagonManager; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; +import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolver; @@ -554,6 +556,7 @@ public class MavenFacadeEmbedderImpl extends RemoteObject implements MavenFacade MavenEmbedder.setImplementation(c, ArtifactFactory.class, CustomArtifactFactory.class); MavenEmbedder.setImplementation(c, ProjectArtifactFactory.class, CustomArtifactFactory.class); MavenEmbedder.setImplementation(c, ArtifactResolver.class, CustomArtifactResolver.class); + MavenEmbedder.setImplementation(c, RepositoryMetadataManager.class, CustomRepositoryMetadataManager.class); MavenEmbedder.setImplementation(c, WagonManager.class, CustomWagonManager.class); MavenEmbedder.setImplementation(c, ModelInterpolator.class, CustomModelInterpolator.class); } @@ -580,6 +583,7 @@ public class MavenFacadeEmbedderImpl extends RemoteObject implements MavenFacade ((CustomArtifactFactory)getComponent(ArtifactFactory.class)).customize(); ((CustomArtifactFactory)getComponent(ProjectArtifactFactory.class)).customize(); ((CustomArtifactResolver)getComponent(ArtifactResolver.class)).customize(projectIdToFileMap, strict); + ((CustomRepositoryMetadataManager)getComponent(RepositoryMetadataManager.class)).customize(projectIdToFileMap); ((CustomWagonManager)getComponent(WagonManager.class)).customize(strict); setConsoleAndLogger(logger, process); @@ -604,6 +608,7 @@ public class MavenFacadeEmbedderImpl extends RemoteObject implements MavenFacade ((CustomArtifactFactory)getComponent(ProjectArtifactFactory.class)).reset(); ((CustomArtifactFactory)getComponent(ArtifactFactory.class)).reset(); ((CustomArtifactResolver)getComponent(ArtifactResolver.class)).reset(); + ((CustomRepositoryMetadataManager)getComponent(RepositoryMetadataManager.class)).reset(); ((CustomWagonManager)getComponent(WagonManager.class)).reset(); } catch (Exception e) { diff --git a/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/MavenFacadeLoggerWrapper.java b/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/MavenFacadeLoggerWrapper.java index 1fdff7a724e5..47c42d6c25a0 100644 --- a/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/MavenFacadeLoggerWrapper.java +++ b/plugins/maven/facade-impl/src/org/jetbrains/idea/maven/facade/embedder/MavenFacadeLoggerWrapper.java @@ -53,4 +53,13 @@ public class MavenFacadeLoggerWrapper { throw new RuntimeException(e1); } } + + public void print(String o) { + try { + myWrappee.print(o); + } + catch (RemoteException e1) { + throw new RuntimeException(e1); + } + } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/facade/MavenFacadeManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/facade/MavenFacadeManager.java index 48591c8face0..0f1715bfab68 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/facade/MavenFacadeManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/facade/MavenFacadeManager.java @@ -168,6 +168,7 @@ public class MavenFacadeManager { } } params.getVMParametersList().addParametersString("-Djava.awt.headless=true -Xmx512m"); + //params.getVMParametersList().addParametersString("-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5009"); return params; } @@ -346,6 +347,10 @@ public class MavenFacadeManager { public void error(Throwable e) { MavenLog.LOG.error(e); } + + public void print(String s) { + System.out.println(s); + } } private static class RemoteMavenFacadeDownloadListener extends RemoteObject implements MavenFacadeDownloadListener { diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/DependenciesImportingTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/DependenciesImportingTest.java index 044731e6bf0b..4dde1d973d22 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/DependenciesImportingTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/DependenciesImportingTest.java @@ -187,7 +187,7 @@ public class DependenciesImportingTest extends MavenImportingTestCase { assertModuleLibDeps("project", "Maven: group:lib:1"); } - public void testIntermoduleDependencies() throws Exception { + public void testInterModuleDependencies() throws Exception { createProjectPom("test" + "project" + "pom" + @@ -196,7 +196,6 @@ public class DependenciesImportingTest extends MavenImportingTestCase { "" + " m1" + " m2" + - " m3" + ""); createModulePom("m1", "test" + @@ -259,6 +258,72 @@ public class DependenciesImportingTest extends MavenImportingTestCase { assertModuleModuleDeps("m1", "m2"); } + public void testInterModuleDependenciesWithVersionRanges() throws Exception { + createProjectPom("test" + + "project" + + "pom" + + "1" + + + "" + + " m1" + + " m2" + + ""); + + createModulePom("m1", "test" + + "m1" + + "1" + + + "" + + " " + + " test" + + " m2" + + " [1, 2]" + + " " + + ""); + + createModulePom("m2", "test" + + "m2" + + "1"); + + importProject(); + assertModules("project", "m1", "m2"); + + assertModuleModuleDeps("m1", "m2"); + } + + public void testInterSnapshotModuleDependenciesWithVersionRanges() throws Exception { + createProjectPom("test" + + "project" + + "pom" + + "1" + + + "" + + " m1" + + " m2" + + ""); + + createModulePom("m1", "test" + + "m1" + + "1" + + + "" + + " " + + " test" + + " m2" + + " [, 1-SNAPSHOT]" + + " " + + ""); + + createModulePom("m2", "test" + + "m2" + + "1-SNAPSHOT"); + + importProject(); + assertModules("project", "m1", "m2"); + + assertModuleModuleDeps("m1", "m2"); + } + public void testInterModuleDependenciesWithoutModuleGroup() throws Exception { createProjectPom("test" + "project" + diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index 45e7114caedb..daff6f2f5c95 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -39,17 +39,17 @@ import com.intellij.util.ThrowableConsumer; import com.intellij.util.containers.MultiMap; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnAuthenticationNotifier; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.actions.ConfigureBranchesAction; -import org.tmatesoft.svn.core.ISVNLogEntryHandler; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNLogEntry; -import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.io.SVNRepository; +import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNWCClient; import java.io.DataInput; import java.io.DataOutput; @@ -490,6 +490,106 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi return 0; } + @Override + public SvnChangeList getOneList(final RepositoryLocation location, VcsRevisionNumber number) throws VcsException { + final String url = ((SvnRepositoryLocation)location).getURL(); + final long revision; + try { + revision = Long.parseLong(number.asString()); + } catch (NumberFormatException e) { + throw new VcsException(e); + } + + final SvnChangeList[] result = new SvnChangeList[1]; + final SVNLogClient logger; + final SVNRevision revisionBefore; + final SVNURL repositoryUrl; + final SVNURL svnurl; + try { + logger = myVcs.createLogClient(); + revisionBefore = SVNRevision.create(revision); + + svnurl = SVNURL.parseURIEncoded(url); + final SVNWCClient client = myVcs.createWCClient(); + SVNInfo info = client.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.HEAD); + if (info == null) { + throw new VcsException("Can not get repository URL"); + } + repositoryUrl = info.getRepositoryRootURL(); + } + catch (SVNException e) { + throw new VcsException(e); + } + + tryExactHit((SvnRepositoryLocation)location, result, logger, revisionBefore, repositoryUrl, svnurl); + if (result[0] == null) { + tryByRoot(result, logger, revisionBefore, repositoryUrl); + if (result[0] == null) { + tryStepByStep((SvnRepositoryLocation)location, result, logger, revisionBefore, repositoryUrl, svnurl); + } + } + return result[0]; + } + + private void tryByRoot(SvnChangeList[] result, SVNLogClient logger, SVNRevision revisionBefore, SVNURL repositoryUrl) throws VcsException { + final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl); + if (! authorized) return; + tryExactHit(new SvnRepositoryLocation(repositoryUrl.toString()), result, logger, revisionBefore, repositoryUrl, repositoryUrl); + } + + private void tryStepByStep(final SvnRepositoryLocation svnRepositoryLocation, + final SvnChangeList[] result, + SVNLogClient logger, + final SVNRevision revisionBefore, final SVNURL repositoryUrl, SVNURL svnurl) throws VcsException { + try { + logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, + false, true, true, 0, null, + new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + if (logEntry.getDate() == null) { + // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe + return; + } + if (logEntry.getRevision() == revisionBefore.getNumber()) { + result[0] = new SvnChangeList(myVcs, svnRepositoryLocation, logEntry, repositoryUrl.toString()); + } + } + }); + } + catch (SVNException e) { + throw new VcsException(e); + } + } + + private void tryExactHit(final SvnRepositoryLocation location, + final SvnChangeList[] result, + SVNLogClient logger, + SVNRevision revisionBefore, + final SVNURL repositoryUrl, SVNURL svnurl) throws VcsException { + try { + logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, + false, true, false, 1, null, + new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + if (logEntry.getDate() == null) { + // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe + return; + } + result[0] = new SvnChangeList(myVcs, (SvnRepositoryLocation) location, logEntry, repositoryUrl.toString()); + } + }); + } + catch (SVNException e) { + if (SVNErrorCode.FS_CATEGORY == e.getErrorMessage().getErrorCode().getCategory()) { + // pass to step by step looking for revision + return; + } + throw new VcsException(e); + } + } + public int getFormatVersion() { return VERSION_WITH_REPLACED_PATHS; } diff --git a/plugins/testng/lib/testng-jdk14.jar b/plugins/testng/lib/testng-jdk14.jar deleted file mode 100644 index 1d9ce88fc074..000000000000 Binary files a/plugins/testng/lib/testng-jdk14.jar and /dev/null differ diff --git a/plugins/testng/lib/testng-jdk15.jar b/plugins/testng/lib/testng-jdk15.jar index 66af11f0fc70..1bce7f89cf93 100644 Binary files a/plugins/testng/lib/testng-jdk15.jar and b/plugins/testng/lib/testng-jdk15.jar differ diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java index 7424fa25ae72..a0ee35761c61 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java @@ -49,6 +49,7 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; @@ -131,6 +132,7 @@ public class TestNGRunnableState extends JavaCommandLineState { executor); console.initUI(); unboundOutputRoot.setPrinter(console.getPrinter()); + Disposer.register(console, unboundOutputRoot); for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) { ext.handleStartProcess(config, processHandler); } diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestNGRemoteListener.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestNGRemoteListener.java index eaec7f802dcc..3b50d832fb55 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/model/TestNGRemoteListener.java +++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestNGRemoteListener.java @@ -46,6 +46,7 @@ public class TestNGRemoteListener implements IRemoteSuiteListener, IRemoteTestLi } public void onFinish(SuiteMessage suiteMessage) { + unboundOutputRoot.flush(); console.finish(); final TestNGResults view = console.getResultsView(); if (view != null) { diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java index ca98bbbcc88b..31a2a4c2d76c 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java +++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java @@ -17,26 +17,18 @@ package com.theoryinpractice.testng.model; import com.intellij.execution.Location; import com.intellij.execution.PsiLocation; -import com.intellij.execution.stacktrace.StackTraceLine; import com.intellij.execution.testframework.AbstractTestProxy; import com.intellij.execution.testframework.Filter; -import com.intellij.execution.testframework.Printable; -import com.intellij.execution.testframework.Printer; -import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.ide.util.EditSourceUtil; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diff.LineTokenizer; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; import com.intellij.pom.Navigatable; import com.intellij.psi.*; -import com.theoryinpractice.testng.ui.TestNGConsoleView; import org.jetbrains.annotations.Nullable; import org.testng.remote.strprotocol.MessageHelper; import org.testng.remote.strprotocol.TestResultMessage; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; /** @@ -49,7 +41,6 @@ public class TestProxy extends AbstractTestProxy { private TestProxy parent; private SmartPsiElementPointer psiElement; private boolean inProgress; - private int myExceptionMark; private boolean myTearDownFailure; public TestProxy() {} @@ -220,24 +211,6 @@ public class TestProxy extends AbstractTestProxy { return null; } - public int getExceptionMark() {//todo - if (myExceptionMark == 0 && getChildCount() > 0) { - return getChildAt(0).getExceptionMark(); - } - return myExceptionMark; - } - - public void setExceptionMark(int exceptionMark) { - myExceptionMark = exceptionMark; - } - - @Override - public void printOn(Printer printer) { - for (int i = 0; i < myNestedPrintables.size(); i++) { - if (i == myExceptionMark && i > 0) printer.mark(); - myNestedPrintables.get(i).printOn(printer); - } - } public boolean isInterrupted() { return !isInProgress() && inProgress; diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGConsoleView.java b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGConsoleView.java index 2e628aca3bdd..3994d8975339 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGConsoleView.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGConsoleView.java @@ -109,19 +109,20 @@ public class TestNGConsoleView extends BaseTestsOutputConsoleView { if (testNGResults != null) { int exceptionMark = myExceptionalMark == -1 ? 0 : myExceptionalMark; - final String stackTrace = result.getStackTrace(); - if (stackTrace != null && stackTrace.length() > 10) { - exceptionMark = currentTest.getCurrentSize(); - //trim useless crud from stacktrace - String trimmed = trimStackTrace(stackTrace); - List printables = getPrintables(result, trimmed); - for (Printable printable : printables) { - currentTest.addLast(printable); + if (currentTest != null) { + final String stackTrace = result.getStackTrace(); + if (stackTrace != null && stackTrace.length() > 10) { + exceptionMark = currentTest.getCurrentSize(); + //trim useless crud from stacktrace + List printables = getPrintables(result); + for (Printable printable : printables) { + currentTest.addLast(printable); + } + } + final TestProxy failedToStart = testNGResults.getFailedToStart(); + if (failedToStart != null) { + currentTest.addChild(failedToStart); } - } - final TestProxy failedToStart = testNGResults.getFailedToStart(); - if (failedToStart != null) { - currentTest.addChild(failedToStart); } testNGResults.addTestResult(result, exceptionMark); myExceptionalMark = -1; @@ -166,7 +167,8 @@ public class TestNGConsoleView extends BaseTestsOutputConsoleView { return builder.toString(); } - private List getPrintables(final TestResultMessage result, String s) { + static List getPrintables(final TestResultMessage result) { + String s = trimStackTrace(result.getStackTrace()); List printables = new ArrayList(); //figure out if we have a diff we need to hyperlink Matcher matcher = COMPARISION_PATTERN.matcher(s); diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java index ddde6b7f8af0..0106adca373b 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java @@ -56,7 +56,6 @@ import java.awt.event.MouseEvent; import java.text.NumberFormat; import java.util.*; import java.util.List; -import java.util.regex.Pattern; public class TestNGResults extends TestResultsPanel implements TestFrameworkRunningModel { @NonNls private static final String TESTNG_SPLITTER_PROPERTY = "TestNG.Splitter.Proportion"; @@ -242,10 +241,18 @@ public class TestNGResults extends TestResultsPanel implements TestFrameworkRunn else { //do not remember testresultmessage: test hierarchy is not set testCase = new TestProxy(result.toDisplayString()); + final String stackTrace = result.getStackTrace(); + if (stackTrace != null) { + final List printables = TestNGConsoleView.getPrintables(result); + for (Printable printable : printables) { + testCase.addLast(printable); + } + } failedToStart = testCase; } testCase.setExceptionMark(exceptionMark); + AbstractTestProxy.flushOutput(testCase); if (result.getResult() == MessageHelper.FAILED_TEST) { myStatusLine.setStatusColor(ColorProgressBar.RED); diff --git a/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java b/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java index 4b752c6d8ae8..e498b6c00bd8 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java +++ b/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java @@ -26,20 +26,17 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.libraries.JarVersionDetectionUtil; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.vfs.*; import com.intellij.psi.*; import com.intellij.psi.impl.source.jsp.jspJava.JspClass; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.TextOccurenceProcessor; -import com.intellij.psi.search.UsageSearchContext; import com.intellij.psi.search.searches.AllClassesSearch; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiElementFilter; @@ -56,9 +53,11 @@ import org.testng.TestNG; import org.testng.annotations.*; import java.io.File; +import java.io.IOException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.zip.ZipFile; /** * @author Hani Suleiman Date: Jul 20, 2005 Time: 1:37:36 PM @@ -68,6 +67,31 @@ public class TestNGUtil private static final Logger LOGGER = Logger.getInstance("TestNG Runner"); public static final String TESTNG_GROUP_NAME = "TestNG"; + public static boolean hasDocTagsSupport = hasDocTagsSupport(); + + private static boolean hasDocTagsSupport() { + final String testngJarPath = PathUtil.getJarPathForClass(Test.class); + if (testngJarPath != null) { + final VirtualFile testngjar = LocalFileSystem.getInstance().findFileByPath(testngJarPath); + if (testngjar != null ) { + try { + final VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(testngjar); + if (jarRoot != null) { + final ZipFile zipFile = JarFileSystem.getInstance().getJarFile(jarRoot); + final String version = JarVersionDetectionUtil.detectJarVersion(zipFile); + if (version != null && version.compareTo("5.12") > 0) { + return false; + } + } + } + catch (IOException e) { + return true; + } + } + } + return true; + } + public static final String TEST_ANNOTATION_FQN = Test.class.getName(); public static final String[] CONFIG_ANNOTATIONS_FQN = { Configuration.class.getName(), @@ -145,12 +169,7 @@ public class TestNGUtil } public static boolean hasTest(PsiModifierListOwner element, boolean checkDisabled) { - return hasTest(element, checkDisabled, !element.getManager().getSearchHelper().processElementsWithWord(new TextOccurenceProcessor() { - @Override - public boolean execute(PsiElement element, int offsetInElement) { - return false; - } - }, GlobalSearchScope.projectScope(element.getProject()), "testng.test", UsageSearchContext.IN_COMMENTS , true)); + return hasTest(element, checkDisabled, hasDocTagsSupport); } public static boolean hasTest(PsiModifierListOwner element, boolean checkDisabled, boolean checkJavadoc) { diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java index da672c0a6d1c..35a1a8754cae 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java @@ -24,7 +24,6 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; @@ -492,8 +491,10 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { ChangeUtil.copyElement((TreeElement)XmlChildRole.START_TAG_NAME_FINDER.findChild(dummyTag), charTableByTree)); final ASTNode childByRole = XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(tag); if (childByRole != null) { - tag.replaceChild(childByRole, - ChangeUtil.copyElement((TreeElement)XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(dummyTag), charTableByTree)); + final TreeElement treeElement = (TreeElement)XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(dummyTag); + if (treeElement != null) { + tag.replaceChild(childByRole, ChangeUtil.copyElement(treeElement, charTableByTree)); + } } return XmlTagNameChangedImpl.createXmlTagNameChanged(model, tag, oldName);