Merge branch 'master' of git@git.labs.intellij.net:idea/community

This commit is contained in:
Kirill Kalishev
2010-07-28 14:03:57 +04:00
86 changed files with 3332 additions and 943 deletions
+9 -3
View File
@@ -136,10 +136,12 @@ private def layoutWin(Map args, String home, Paths paths) {
patchPropertiesFile(paths.distWin)
ant.echo(file: "$paths.distWin/bin/idea.exe.vmoptions", message: args.vmoptions.replace(' ', '\n'))
ant.zip(zipfile: "$paths.artifacts/idea${args.buildNumber}.win.zip") {
def winZipPath = "$paths.artifacts/idea${args.buildNumber}.win.zip"
ant.zip(zipfile: winZipPath) {
fileset(dir: paths.distAll)
fileset(dir: paths.distWin)
}
notifyArtifactBuilt(winZipPath)
}
private def layoutMac(Map args, String home, Paths paths) {
@@ -170,7 +172,8 @@ private def layoutMac(Map args, String home, Paths paths) {
def root = isEap() ? "${version}-${args.buildNumber}.app" : "IntelliJ IDEA ${version} CE.app"
ant.zip(zipfile: "$paths.artifacts/idea${args.buildNumber}.mac.zip") {
def macZipPath = "$paths.artifacts/idea${args.buildNumber}.mac.zip"
ant.zip(zipfile: macZipPath) {
[paths.distAll, paths.distMac].each {
tarfileset(dir: it, prefix: root) {
exclude(name: "bin/*.sh")
@@ -183,6 +186,7 @@ private def layoutMac(Map args, String home, Paths paths) {
include(name: "Contents/MacOS/idea")
}
}
notifyArtifactBuilt(macZipPath)
}
def layoutLinux(Map args, String home, Paths paths) {
@@ -216,7 +220,9 @@ def layoutLinux(Map args, String home, Paths paths) {
}
}
ant.gzip(src: tarPath, zipfile: "${tarPath}.gz")
def gzPath = "${tarPath}.gz"
ant.gzip(src: tarPath, zipfile: gzPath)
ant.delete(file: tarPath)
notifyArtifactBuilt(gzPath)
}
+8
View File
@@ -88,3 +88,11 @@ binding.setVariable("loadProject", {
requireProperty("home", guessHome())
project.builder.buildInfoPrinter = new org.jetbrains.jps.teamcity.TeamcityBuildInfoPrinter()
binding.setVariable("notifyArtifactBuilt", { String artifactPath ->
if (!artifactPath.startsWith(home)) {
project.error("Artifact path $artifactPath should start with $home")
}
def relativePath = artifactPath.substring(home.length())
project.info("##teamcity[publishArtifacts '$relativePath']")
})
@@ -29,7 +29,6 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.impl.compiler.IncrementalArtifactsCompiler;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Chunk;
import com.intellij.util.containers.ContainerUtil;
@@ -68,7 +67,6 @@ public class CompilerManagerImpl extends CompilerManager {
addTranslatingCompiler(new JavaCompiler(project), new HashSet<FileType>(Arrays.asList(StdFileTypes.JAVA)), new HashSet<FileType>(Arrays.asList(StdFileTypes.CLASS)));
addCompiler(new ResourceCompiler(project, compilerConfiguration));
addCompiler(new RmicCompiler());
addCompiler(new IncrementalArtifactsCompiler());
for(Compiler compiler: Extensions.getExtensions(Compiler.EP_NAME, myProject)) {
addCompiler(compiler);
@@ -24,6 +24,7 @@ package com.intellij.compiler.impl;
import com.intellij.CommonBundle;
import com.intellij.analysis.AnalysisScope;
import com.intellij.compiler.*;
import com.intellij.compiler.impl.newApi.NewCompiler;
import com.intellij.compiler.make.CacheCorruptedException;
import com.intellij.compiler.make.CacheUtils;
import com.intellij.compiler.make.DependencyCache;
@@ -560,7 +561,7 @@ public class CompileDriver {
return CompilerBundle.message("status.compilation.completed.successfully.with.warnings.and.errors", errorCount, warningCount);
}
private static class ExitStatus {
static class ExitStatus {
private final String myName;
private ExitStatus(@NonNls String name) {
@@ -577,10 +578,10 @@ public class CompileDriver {
public static final ExitStatus UP_TO_DATE = new ExitStatus("UP_TO_DATE");
}
private static class ExitException extends Exception {
static class ExitException extends Exception {
private final ExitStatus myStatus;
private ExitException(ExitStatus status) {
ExitException(ExitStatus status) {
myStatus = status;
}
@@ -724,7 +725,7 @@ public class CompileDriver {
boolean didSomething = false;
final CompilerManager compilerManager = CompilerManager.getInstance(myProject);
NewCompilerRunner runner = new NewCompilerRunner(context, compilerManager, forceCompile, onlyCheckStatus);
try {
didSomething |= generateSources(compilerManager, context, forceCompile, onlyCheckStatus);
@@ -746,19 +747,23 @@ public class CompileDriver {
didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassInstrumentingCompiler.class,
FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus);
didSomething |= runner.invokeCompilers(NewCompiler.CompileOrderPlace.CLASS_INSTRUMENTING);
// explicitly passing forceCompile = false because in scopes that is narrower than ProjectScope it is impossible
// to understand whether the class to be processed is in scope or not. Otherwise compiler may process its items even if
// there were changes in completely independent files.
didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassPostProcessingCompiler.class,
FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus);
didSomething |= runner.invokeCompilers(NewCompiler.CompileOrderPlace.CLASS_POST_PROCESSING);
didSomething |= invokeFileProcessingCompilers(compilerManager, context, PackagingCompiler.class,
FILE_PACKAGING_COMPILER_ADAPTER_FACTORY,
isRebuild, false, onlyCheckStatus);
didSomething |= runner.invokeCompilers(NewCompiler.CompileOrderPlace.PACKAGING);
didSomething |= invokeFileProcessingCompilers(compilerManager, context, Validator.class, FILE_PROCESSING_COMPILER_ADAPTER_FACTORY,
forceCompile, true, onlyCheckStatus);
didSomething |= runner.invokeCompilers(NewCompiler.CompileOrderPlace.VALIDATING);
}
catch (ExitException e) {
if (LOG.isDebugEnabled()) {
@@ -15,6 +15,8 @@
*/
package com.intellij.compiler.impl;
import com.intellij.compiler.impl.newApi.NewCompiler;
import com.intellij.compiler.impl.newApi.NewCompilerCache;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.compiler.Compiler;
@@ -42,6 +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<Compiler, Object> myCompilerToCacheMap = new HashMap<Compiler, Object>();
private final Map<NewCompiler<?,?>, NewCompilerCache<?,?>> myNewCachesMap = new HashMap<NewCompiler<?,?>, NewCompilerCache<?,?>>();
private final List<Disposable> myCacheDisposables = new ArrayList<Disposable>();
private final File myCachesRoot;
private final Runnable myShutdownTask = new Runnable() {
@@ -49,8 +52,10 @@ public class CompilerCacheManager implements ProjectComponent {
flushCaches();
}
};
private final Project myProject;
public CompilerCacheManager(Project project) {
myProject = project;
myCachesRoot = CompilerPaths.getCacheStoreDirectory(project);
}
@@ -85,6 +90,23 @@ public class CompilerCacheManager implements ProjectComponent {
return dir;
}
public synchronized <Key, State> NewCompilerCache<Key, State> getNewCompilerCache(NewCompiler<Key, State> compiler) throws IOException {
NewCompilerCache<?, ?> cache = myNewCachesMap.get(compiler);
if (cache == null) {
final NewCompilerCache<?, ?> newCache = new NewCompilerCache<Key, State>(compiler, NewCompilerRunner.getNewCompilerCacheDir(myProject, compiler));
myNewCachesMap.put(compiler, newCache);
myCacheDisposables.add(new Disposable() {
@Override
public void dispose() {
newCache.close();
}
});
cache = newCache;
}
//noinspection unchecked
return (NewCompilerCache<Key, State>)cache;
}
public synchronized FileProcessingCompilerStateCache getFileProcessingCompilerCache(FileProcessingCompiler compiler) throws IOException {
Object cache = myCompilerToCacheMap.get(compiler);
if (cache == null) {
@@ -0,0 +1,246 @@
/*
* 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;
import com.intellij.compiler.impl.newApi.*;
import com.intellij.openapi.application.ApplicationManager;
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;
import com.intellij.util.io.KeyDescriptor;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author nik
*/
public class NewCompilerRunner {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.NewCompilerRunner");
private CompileContext myContext;
private final boolean myForceCompile;
private final boolean myOnlyCheckStatus;
private final NewCompiler<?,?>[] myCompilers;
private final Project myProject;
public NewCompilerRunner(CompileContext context, CompilerManager compilerManager, boolean forceCompile, boolean onlyCheckStatus) {
myContext = context;
myForceCompile = forceCompile;
myOnlyCheckStatus = onlyCheckStatus;
myCompilers = compilerManager.getCompilers(NewCompiler.class);
myProject = myContext.getProject();
}
public boolean invokeCompilers(NewCompiler.CompileOrderPlace place) throws CompileDriver.ExitException {
boolean didSomething = false;
try {
for (NewCompiler<?, ?> compiler : myCompilers) {
if (compiler.getOrderPlace().equals(place)) {
didSomething = invokeCompiler(compiler);
}
}
}
catch (IOException e) {
LOG.info(e);
myContext.requestRebuildNextTime(e.getMessage());
throw new CompileDriver.ExitException(CompileDriver.ExitStatus.ERRORS);
}
catch (CompileDriver.ExitException e) {
throw e;
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Exception e) {
LOG.info(e);
myContext.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.exception", e.getMessage()), null, -1, -1);
}
return didSomething;
}
private <T extends BuildTarget, Key, State> boolean invokeCompiler(NewCompiler<Key, State> compiler) throws IOException, CompileDriver.ExitException {
return invokeCompiler(compiler, compiler.createInstance(myContext));
}
private <T extends BuildTarget, Item extends CompileItem<Key, State>, Key, State>
boolean invokeCompiler(NewCompiler<Key, State> compiler, CompilerInstance<T, Item, Key, State> instance) throws IOException, CompileDriver.ExitException {
NewCompilerCache<Key, State> 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());
cache.wipe();
}
Set<String> targetsToRemove = new HashSet<String>(data.getAllTargets());
for (T target : instance.getAllTargets()) {
targetsToRemove.remove(target.getId());
}
if (!myOnlyCheckStatus) {
for (String target : targetsToRemove) {
int id = data.removeId(target);
if (LOG.isDebugEnabled()) {
LOG.debug("Removing obsolete target '" + target + "' (id=" + id + ")");
}
List<Key> keys = new ArrayList<Key>();
cache.processSources(id, new CommonProcessors.CollectProcessor<Key>(keys));
List<Pair<Key, State>> obsoleteSources = new ArrayList<Pair<Key, State>>();
for (Key key : keys) {
final State state = cache.getState(id, key);
obsoleteSources.add(Pair.create(key, state));
}
instance.processObsoleteTarget(target, obsoleteSources);
if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
return true;
}
for (Key key : keys) {
cache.remove(id, key);
}
}
}
boolean didSomething = false;
for (T target : instance.getSelectedTargets()) {
int id = data.getId(target.getId());
didSomething |= processTarget(target, id, compiler, instance, cache);
}
data.save();
return didSomething;
}
public static File getNewCompilerCacheDir(Project project, NewCompiler<?, ?> compiler) {
return new File(CompilerPaths.getCacheStoreDirectory(project), compiler.getId());
}
private <T extends BuildTarget, Item extends CompileItem<Key, State>, Key, State>
boolean processTarget(T target, final int targetId, final NewCompiler<Key, State> compiler, final CompilerInstance<T, Item, Key, State> instance,
final NewCompilerCache<Key, State> cache) throws IOException, CompileDriver.ExitException {
if (LOG.isDebugEnabled()) {
LOG.debug("Processing target '" + target + "' (id=" + targetId + ")");
}
final List<Item> items = instance.getItems(target);
if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) return true;
final List<Pair<Item, State>> toProcess = new ArrayList<Pair<Item, State>>();
final THashSet<Key> keySet = new THashSet<Key>(new SourceItemHashingStrategy<Key>(compiler));
final Ref<IOException> exception = Ref.create(null);
DumbService.getInstance(myProject).waitForSmartMode();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
try {
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));
}
}
}
catch (IOException e) {
exception.set(e);
}
}
});
if (!exception.isNull()) {
throw exception.get();
}
final List<Key> toRemove = new ArrayList<Key>();
cache.processSources(targetId, new Processor<Key>() {
@Override
public boolean process(Key key) {
if (!keySet.contains(key)) {
toRemove.add(key);
}
return true;
}
});
if (LOG.isDebugEnabled()) {
LOG.debug(toProcess.size() + " items will be processed, " + toRemove.size() + " items will be removed");
}
if (toProcess.isEmpty() && toRemove.isEmpty()) {
return false;
}
if (myOnlyCheckStatus) {
throw new CompileDriver.ExitException(CompileDriver.ExitStatus.CANCELLED);
}
List<Pair<Key, State>> obsoleteItems = new ArrayList<Pair<Key, State>>();
for (Key key : toRemove) {
obsoleteItems.add(Pair.create(key, cache.getState(targetId, key)));
}
final List<Item> processedItems = new ArrayList<Item>();
final List<File> toRefresh = new ArrayList<File>();
instance.processItems(target, toProcess, obsoleteItems, new CompilerInstance.OutputConsumer<Item>() {
@Override
public void addFileToRefresh(@NotNull File file) {
toRefresh.add(file);
}
@Override
public void addProcessedItem(@NotNull Item sourceItem) {
processedItems.add(sourceItem);
}
});
if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
return true;
}
for (Key key : toRemove) {
cache.remove(targetId, key);
}
CompilerUtil.refreshIOFiles(toRefresh);
for (Item item : processedItems) {
cache.putOutput(targetId, item.getKey(), item.computeState());
}
return true;
}
private class SourceItemHashingStrategy<S> implements TObjectHashingStrategy<S> {
private KeyDescriptor<S> myKeyDescriptor;
public SourceItemHashingStrategy(NewCompiler<S, ?> compiler) {
myKeyDescriptor = compiler.getItemKeyDescriptor();
}
@Override
public int computeHashCode(S object) {
return myKeyDescriptor.getHashCode(object);
}
@Override
public boolean equals(S o1, S o2) {
return myKeyDescriptor.isEqual(o1, o2);
}
}
}
@@ -0,0 +1,39 @@
/*
* 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;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public abstract class BuildTarget {
public static final BuildTarget DEFAULT = new BuildTarget() {
@NotNull
@Override
public String getId() {
return "<default>";
}
};
@NotNull
public abstract String getId();
@Override
public String toString() {
return "Build Target: " + getId();
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.impl.newApi;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public abstract class CompileItem<Key, State> {
@NotNull
public abstract Key getKey();
public abstract boolean isUpToDate(@NotNull State state);
@NotNull
public abstract State computeState();
}
@@ -0,0 +1,60 @@
/*
* 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;
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;
import java.util.List;
/**
* @author nik
*/
public abstract class CompilerInstance<T extends BuildTarget, Item extends CompileItem<Key, State>, Key, State> {
protected final CompileContext myContext;
protected CompilerInstance(CompileContext context) {
myContext = context;
}
protected Project getProject() {
return myContext.getProject();
}
@NotNull
public abstract List<T> getAllTargets();
@NotNull
public abstract List<T> getSelectedTargets();
public abstract void processObsoleteTarget(@NotNull String targetId, @NotNull List<Pair<Key, State>> obsoleteItems);
@NotNull
public abstract List<Item> getItems(@NotNull T target);
public abstract void processItems(@NotNull T target, @NotNull List<Pair<Item, State>> changedItems, @NotNull List<Pair<Key, State>> obsoleteItems,
@NotNull OutputConsumer<Item> consumer);
public interface OutputConsumer<Item extends CompileItem<?,?>> {
void addFileToRefresh(@NotNull File file);
void addProcessedItem(@NotNull Item sourceItem);
}
}
@@ -0,0 +1,62 @@
/*
* 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;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.Compiler;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public abstract class NewCompiler<Key, State> implements Compiler {
private final String myId;
private final int myVersion;
private final CompileOrderPlace myOrderPlace;
protected NewCompiler(@NotNull String id, int version, @NotNull CompileOrderPlace orderPlace) {
myId = id;
myVersion = version;
myOrderPlace = orderPlace;
}
@NotNull
public abstract KeyDescriptor<Key> getItemKeyDescriptor();
@NotNull
public abstract DataExternalizer<State> getItemStateExternalizer();
@NotNull
public abstract CompilerInstance<?, ? extends CompileItem<Key, State>, Key, State> createInstance(@NotNull CompileContext context);
public final String getId() {
return myId;
}
public final int getVersion() {
return myVersion;
}
public CompileOrderPlace getOrderPlace() {
return myOrderPlace;
}
public static enum CompileOrderPlace {
CLASS_INSTRUMENTING, CLASS_POST_PROCESSING, PACKAGING, VALIDATING
}
}
@@ -0,0 +1,132 @@
/*
* 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;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.Processor;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentHashMap;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
/**
* @author nik
*/
public class NewCompilerCache<Key, State> {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.newApi.NewCompilerCache");
private PersistentHashMap<KeyAndTargetData<Key>, State> myPersistentMap;
private File myCacheFile;
private final NewCompiler<Key, State> myCompiler;
public NewCompilerCache(NewCompiler<Key, State> compiler, final File compilerCacheDir) throws IOException {
myCompiler = compiler;
myCacheFile = new File(compilerCacheDir, "timestamps");
createMap();
}
private void createMap() throws IOException {
myPersistentMap = new PersistentHashMap<KeyAndTargetData<Key>, State>(myCacheFile, new SourceItemDataDescriptor(myCompiler.getItemKeyDescriptor()),
myCompiler.getItemStateExternalizer());
}
private KeyAndTargetData<Key> getKeyAndTargetData(Key key, int target) {
KeyAndTargetData<Key> data = new KeyAndTargetData<Key>();
data.myTarget = target;
data.myKey = key;
return data;
}
public void wipe() throws IOException {
try {
myPersistentMap.close();
}
catch (IOException ignored) {
}
PersistentHashMap.deleteFilesStartingWith(myCacheFile);
createMap();
}
public void close() {
try {
myPersistentMap.close();
}
catch (IOException e) {
LOG.info(e);
}
}
public void remove(int targetId, Key key) throws IOException {
myPersistentMap.remove(getKeyAndTargetData(key, targetId));
}
public State getState(int targetId, Key key) throws IOException {
return myPersistentMap.get(getKeyAndTargetData(key, targetId));
}
public void processSources(final int targetId, final Processor<Key> processor) throws IOException {
myPersistentMap.processKeys(new Processor<KeyAndTargetData<Key>>() {
@Override
public boolean process(KeyAndTargetData<Key> data) {
return targetId == data.myTarget ? processor.process(data.myKey) : true;
}
});
}
public void putOutput(int targetId, Key key, State outputItem) throws IOException {
myPersistentMap.put(getKeyAndTargetData(key, targetId), outputItem);
}
private static class KeyAndTargetData<Key> {
public int myTarget;
public Key myKey;
}
private class SourceItemDataDescriptor implements KeyDescriptor<KeyAndTargetData<Key>> {
private final KeyDescriptor<Key> myKeyDescriptor;
public SourceItemDataDescriptor(KeyDescriptor<Key> keyDescriptor) {
myKeyDescriptor = keyDescriptor;
}
@Override
public boolean isEqual(KeyAndTargetData<Key> val1, KeyAndTargetData<Key> val2) {
return val1.myTarget == val2.myTarget;
}
@Override
public int getHashCode(KeyAndTargetData<Key> value) {
return value.myTarget + 239 * myKeyDescriptor.getHashCode(value.myKey);
}
@Override
public void save(DataOutput out, KeyAndTargetData<Key> value) throws IOException {
out.writeInt(value.myTarget);
myKeyDescriptor.save(out, value.myKey);
}
@Override
public KeyAndTargetData<Key> read(DataInput in) throws IOException {
int target = in.readInt();
final Key item = myKeyDescriptor.read(in);
return getKeyAndTargetData(item, target);
}
}
}
@@ -0,0 +1,119 @@
/*
* 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;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.io.IOUtil;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author nik
*/
public class NewCompilerPersistentData {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.newApi.NewCompilerPersistentData");
private static final int VERSION = 0;
private File myFile;
private Map<String, Integer> myTarget2Id = new HashMap<String, Integer>();
private TIntHashSet myUsedIds = new TIntHashSet();
private boolean myVersionChanged;
private final int myCompilerVersion;
public NewCompilerPersistentData(File cacheStoreDirectory, int compilerVersion) throws IOException {
myCompilerVersion = compilerVersion;
myFile = new File(cacheStoreDirectory, "info");
if (!myFile.exists()) {
LOG.info("Compiler info file doesn't exists: " + myFile.getAbsolutePath());
myVersionChanged = true;
return;
}
DataInputStream input = new DataInputStream(new FileInputStream(myFile));
try {
final int dataVersion = input.readInt();
if (dataVersion != VERSION) {
LOG.info("Version of compiler info file (" + myFile.getAbsolutePath() + ") changed: " + dataVersion + " -> " + VERSION);
myVersionChanged = true;
return;
}
final int savedCompilerVersion = input.readInt();
if (savedCompilerVersion != compilerVersion) {
LOG.info("Compiler caches version changed (" + myFile.getAbsolutePath() + "): " + savedCompilerVersion + " -> " + compilerVersion);
myVersionChanged = true;
return;
}
int size = input.readInt();
while (size-- > 0) {
final String target = IOUtil.readString(input);
final int id = input.readInt();
myTarget2Id.put(target, id);
myUsedIds.add(id);
}
}
finally {
input.close();
}
}
public boolean isVersionChanged() {
return myVersionChanged;
}
public void save() throws IOException {
final DataOutputStream output = new DataOutputStream(new FileOutputStream(myFile));
try {
output.writeInt(VERSION);
output.writeInt(myCompilerVersion);
output.writeInt(myTarget2Id.size());
for (Map.Entry<String, Integer> entry : myTarget2Id.entrySet()) {
IOUtil.writeString(entry.getKey(), output);
output.writeInt(entry.getValue());
}
}
finally {
output.close();
}
}
public int getId(@NotNull String target) {
if (myTarget2Id.containsKey(target)) {
return myTarget2Id.get(target);
}
int id = 0;
while (myUsedIds.contains(id)) {
id++;
}
myTarget2Id.put(target, id);
myUsedIds.add(id);
return id;
}
public Set<String> getAllTargets() {
return myTarget2Id.keySet();
}
public int removeId(String target) {
return myTarget2Id.remove(target);
}
}
@@ -0,0 +1,48 @@
/*
* 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;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
/**
* @author nik
*/
public abstract class SingleTargetCompilerInstance<Item extends CompileItem<S,O>, S, O> extends CompilerInstance<BuildTarget, Item, S, O> {
protected SingleTargetCompilerInstance(CompileContext context) {
super(context);
}
@NotNull
@Override
public List<BuildTarget> getAllTargets() {
return Collections.singletonList(BuildTarget.DEFAULT);
}
@NotNull
@Override
public List<BuildTarget> getSelectedTargets() {
return getAllTargets();
}
@Override
public void processObsoleteTarget(@NotNull String targetId, @NotNull List<Pair<S, O>> obsoleteItems) {
}
}
@@ -0,0 +1,55 @@
/*
* 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;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public abstract class VirtualFileCompileItem<State extends VirtualFilePersistentState> extends CompileItem<String, State> {
public static final KeyDescriptor<String> KEY_DESCRIPTOR = new EnumeratorStringDescriptor();
protected final VirtualFile myFile;
public VirtualFileCompileItem(@NotNull VirtualFile file) {
myFile = file;
}
@NotNull
public VirtualFile getFile() {
return myFile;
}
@Override
public final boolean isUpToDate(@NotNull State state) {
if (myFile.getTimeStamp() != state.getSourceTimestamp()) {
return false;
}
return isStateUpToDate(state);
}
protected abstract boolean isStateUpToDate(State state);
@NotNull
@Override
public String getKey() {
return myFile.getUrl();
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.impl.newApi;
/**
* @author nik
*/
public class VirtualFilePersistentState {
private final long mySourceTimestamp;
public VirtualFilePersistentState(long sourceTimestamp) {
mySourceTimestamp = sourceTimestamp;
}
public final long getSourceTimestamp() {
return mySourceTimestamp;
}
}
@@ -0,0 +1,44 @@
/*
* 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;
import com.intellij.util.io.DataExternalizer;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* @author nik
*/
public abstract class VirtualFileStateExternalizer<State extends VirtualFilePersistentState> implements DataExternalizer<State> {
protected abstract void doSave(DataOutput out, State value) throws IOException;
protected abstract State doRead(DataInput in, long sourceTimestamp) throws IOException;
@Override
public final void save(DataOutput out, State 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);
}
}
@@ -16,9 +16,9 @@
package com.intellij.compiler.impl.packagingCompiler;
import com.intellij.openapi.deployment.DeploymentUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
/**
* @author nik
@@ -29,12 +29,18 @@ public class JarDestinationInfo extends DestinationInfo {
private final JarInfo myJarInfo;
public JarDestinationInfo(final String pathInJar, final JarInfo jarInfo, DestinationInfo jarDestination) {
super(DeploymentUtil.appendToPath(jarDestination.getOutputPath(), pathInJar), jarDestination.getOutputFile(), jarDestination.getOutputFilePath());
super(appendPathInJar(jarDestination.getOutputPath(), pathInJar), jarDestination.getOutputFile(), jarDestination.getOutputFilePath());
LOG.assertTrue(!pathInJar.startsWith(".."), pathInJar);
myPathInJar = StringUtil.startsWithChar(pathInJar, '/') ? pathInJar : "/" + pathInJar;
myJarInfo = jarInfo;
}
private static String appendPathInJar(String outputPath, String pathInJar) {
LOG.assertTrue(outputPath.length() > 0 && outputPath.charAt(outputPath.length() - 1) != '/');
LOG.assertTrue(pathInJar.length() > 0 && pathInJar.charAt(0) != '/');
return outputPath + JarFileSystem.JAR_SEPARATOR + pathInJar;
}
public String getPathInJar() {
return myPathInJar;
}
@@ -35,7 +35,7 @@ public class ArtifactAdditionalCompileScopeProvider extends AdditionalCompileSco
if (ArtifactCompileScope.getArtifacts(baseScope) != null) {
return null;
}
final IncrementalArtifactsCompiler compiler = IncrementalArtifactsCompiler.getInstance(project);
final ArtifactsCompiler compiler = ArtifactsCompiler.getInstance(project);
if (compiler == null || !filter.acceptCompiler(compiler)) {
return null;
}
@@ -0,0 +1,41 @@
/*
* 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.packaging.impl.compiler;
import com.intellij.compiler.impl.newApi.BuildTarget;
import com.intellij.packaging.artifacts.Artifact;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public class ArtifactBuildTarget extends BuildTarget {
private Artifact myArtifact;
public ArtifactBuildTarget(Artifact artifact) {
myArtifact = artifact;
}
public Artifact getArtifact() {
return myArtifact;
}
@NotNull
@Override
public String getId() {
return myArtifact.getName();
}
}
@@ -0,0 +1,86 @@
/*
* 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.packaging.impl.compiler;
import com.intellij.compiler.impl.newApi.VirtualFileCompileItem;
import com.intellij.compiler.impl.packagingCompiler.DestinationInfo;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.SmartList;
import com.intellij.util.io.DataExternalizer;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author nik
*/
public class ArtifactCompilerCompileItem extends VirtualFileCompileItem<ArtifactPackagingItemOutputState> {
public static final DataExternalizer<ArtifactPackagingItemOutputState> OUTPUT_EXTERNALIZER = new ArtifactPackagingItemExternalizer();
private final List<DestinationInfo> myDestinations = new SmartList<DestinationInfo>();
public ArtifactCompilerCompileItem(VirtualFile file) {
super(file);
}
public void addDestination(DestinationInfo info) {
myDestinations.add(info);
}
public List<DestinationInfo> getDestinations() {
return myDestinations;
}
@NotNull
@Override
public ArtifactPackagingItemOutputState computeState() {
final SmartList<Pair<String, Long>> pairs = new SmartList<Pair<String, Long>>();
for (DestinationInfo destination : myDestinations) {
destination.update();
final VirtualFile outputFile = destination.getOutputFile();
long timestamp = outputFile != null ? outputFile.getTimeStamp() : -1;
pairs.add(Pair.create(destination.getOutputPath(), timestamp));
}
return new ArtifactPackagingItemOutputState(myFile.getTimeStamp(), pairs);
}
@Override
public boolean isStateUpToDate(ArtifactPackagingItemOutputState state) {
final SmartList<Pair<String, Long>> cachedDestinations = state.myDestinations;
if (cachedDestinations.size() != myDestinations.size()) {
return false;
}
for (DestinationInfo info : myDestinations) {
final VirtualFile outputFile = info.getOutputFile();
long timestamp = outputFile != null ? outputFile.getTimeStamp() : -1;
final String path = info.getOutputPath();
boolean found = false;
//todo[nik] use map if list contains many items
for (Pair<String, Long> cachedDestination : cachedDestinations) {
if (cachedDestination.first.equals(path)) {
if (cachedDestination.second != timestamp) return false;
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
}
@@ -0,0 +1,54 @@
/*
* 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.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.IOUtil;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* @author nik
*/
public class ArtifactPackagingItemExternalizer
extends VirtualFileStateExternalizer<ArtifactPackagingItemOutputState> {
private byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer();
@Override
protected void doSave(DataOutput out, ArtifactPackagingItemOutputState value) throws IOException {
out.writeInt(value.myDestinations.size());
for (Pair<String, Long> pair : value.myDestinations) {
IOUtil.writeUTFFast(myBuffer, out, pair.getFirst());
out.writeLong(pair.getSecond());
}
}
@Override
protected ArtifactPackagingItemOutputState doRead(DataInput in, long sourceTimestamp) throws IOException {
int size = in.readInt();
SmartList<Pair<String, Long>> destinations = new SmartList<Pair<String, Long>>();
while (size-- > 0) {
String path = IOUtil.readUTFFast(myBuffer, in);
long outputTimestamp = in.readLong();
destinations.add(Pair.create(path, outputTimestamp));
}
return new ArtifactPackagingItemOutputState(sourceTimestamp, destinations);
}
}
@@ -0,0 +1,32 @@
/*
* 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.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 final SmartList<Pair<String, Long>> myDestinations;
public ArtifactPackagingItemOutputState(long timestamp, SmartList<Pair<String, Long>> destinations) {
super(timestamp);
myDestinations = destinations;
}
}
@@ -1,102 +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.packaging.impl.compiler;
import com.intellij.compiler.impl.packagingCompiler.DestinationInfo;
import com.intellij.openapi.compiler.ValidityState;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.SmartList;
import com.intellij.util.StringSetSpinAllocator;
import com.intellij.util.io.IOUtil;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
* @author nik
*/
public class ArtifactPackagingItemValidityState implements ValidityState {
private final SmartList<Pair<String, Long>> myDestinations;
public ArtifactPackagingItemValidityState(List<DestinationInfo> destinationInfos, boolean sourceFileModified,
@Nullable ArtifactPackagingItemValidityState oldState) {
myDestinations = new SmartList<Pair<String, Long>>();
final Set<String> paths = StringSetSpinAllocator.alloc();
try {
for (DestinationInfo info : destinationInfos) {
final VirtualFile outputFile = info.getOutputFile();
long timestamp = outputFile != null ? outputFile.getTimeStamp() : -1;
final String path = info.getOutputPath();
myDestinations.add(Pair.create(path, timestamp));
paths.add(path);
}
if (!sourceFileModified && oldState != null) {
for (Pair<String, Long> pair : oldState.myDestinations) {
if (!paths.contains(pair.getFirst())) {
myDestinations.add(pair);
}
}
}
}
finally {
StringSetSpinAllocator.dispose(paths);
}
}
public ArtifactPackagingItemValidityState(DataInput input) throws IOException {
int size = input.readInt();
myDestinations = new SmartList<Pair<String, Long>>();
while (size-- > 0) {
String path = IOUtil.readString(input);
long timestamp = input.readLong();
myDestinations.add(Pair.create(path, timestamp));
}
}
public boolean equalsTo(final ValidityState otherState) {
if (!(otherState instanceof ArtifactPackagingItemValidityState)) {
return false;
}
final SmartList<Pair<String, Long>> otherDestinations = ((ArtifactPackagingItemValidityState)otherState).myDestinations;
if (otherDestinations.size() != myDestinations.size()) {
return false;
}
if (myDestinations.size() == 1) {
return myDestinations.get(0).equals(otherDestinations.get(0));
}
return Comparing.haveEqualElements(myDestinations, otherDestinations);
}
public void save(final DataOutput output) throws IOException {
output.writeInt(myDestinations.size());
for (Pair<String, Long> pair : myDestinations) {
IOUtil.writeString(pair.getFirst(), output);
output.writeLong(pair.getSecond());
}
}
}
@@ -1,96 +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.packaging.impl.compiler;
import com.intellij.compiler.impl.FileProcessingCompilerStateCache;
import com.intellij.compiler.impl.packagingCompiler.DestinationInfo;
import com.intellij.openapi.compiler.FileProcessingCompiler;
import com.intellij.openapi.compiler.ValidityState;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.List;
/**
* @author nik
*/
public class ArtifactPackagingProcessingItem implements FileProcessingCompiler.ProcessingItem {
private final VirtualFile mySourceFile;
private final List<Pair<DestinationInfo, Boolean>> myDestinations = new SmartList<Pair<DestinationInfo, Boolean>>();
private List<DestinationInfo> myEnabledDestinations;
private boolean mySourceFileModified;
private ArtifactPackagingItemValidityState myOldState;
public ArtifactPackagingProcessingItem(final VirtualFile sourceFile) {
mySourceFile = sourceFile;
}
@NotNull
public VirtualFile getFile() {
return mySourceFile;
}
public void addDestination(DestinationInfo info, boolean enabled) {
for (int i = 0; i < myDestinations.size(); i++) {
Pair<DestinationInfo, Boolean> pair = myDestinations.get(i);
if (info.getOutputPath().equals(pair.getFirst().getOutputPath())) {
if (enabled && !pair.getSecond()) {
myDestinations.set(i, Pair.create(info, true));
}
return;
}
}
myDestinations.add(Pair.create(info, enabled));
}
public List<Pair<DestinationInfo, Boolean>> getDestinations() {
return myDestinations;
}
public void init(FileProcessingCompilerStateCache cache) throws IOException {
final String url = mySourceFile.getUrl();
myOldState = (ArtifactPackagingItemValidityState)cache.getExtState(url);
mySourceFileModified = cache.getTimestamp(url) != mySourceFile.getTimeStamp();
}
public void setProcessed() {
for (DestinationInfo destination : myEnabledDestinations) {
destination.update();
}
}
public List<DestinationInfo> getEnabledDestinations() {
if (myEnabledDestinations == null) {
myEnabledDestinations = new SmartList<DestinationInfo>();
for (Pair<DestinationInfo, Boolean> destination : myDestinations) {
if (destination.getSecond()) {
myEnabledDestinations.add(destination.getFirst());
}
}
}
return myEnabledDestinations;
}
@Nullable
public ValidityState getValidityState() {
return new ArtifactPackagingItemValidityState(getEnabledDestinations(), mySourceFileModified, myOldState);
}
}
@@ -0,0 +1,88 @@
/*
* 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.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.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* @author nik
*/
public class ArtifactsCompiler extends NewCompiler<String, ArtifactPackagingItemOutputState> {
static final Key<Set<String>> WRITTEN_PATHS_KEY = Key.create("artifacts_written_paths");
static final Key<Set<Artifact>> AFFECTED_ARTIFACTS = Key.create("affected_artifacts");
public ArtifactsCompiler() {
super("artifacts_compiler", 0, NewCompiler.CompileOrderPlace.PACKAGING);
}
@Nullable
public static ArtifactsCompiler getInstance(@NotNull Project project) {
final ArtifactsCompiler[] compilers = CompilerManager.getInstance(project).getCompilers(ArtifactsCompiler.class);
return compilers.length == 1 ? compilers[0] : null;
}
@NotNull
@Override
public KeyDescriptor<String> getItemKeyDescriptor() {
return VirtualFileCompileItem.KEY_DESCRIPTOR;
}
@NotNull
@Override
public DataExternalizer<ArtifactPackagingItemOutputState> getItemStateExternalizer() {
return ArtifactCompilerCompileItem.OUTPUT_EXTERNALIZER;
}
@NotNull
@Override
public CompilerInstance<ArtifactBuildTarget, ? extends CompileItem<String, ArtifactPackagingItemOutputState>, String, ArtifactPackagingItemOutputState> createInstance(
@NotNull CompileContext context) {
return new ArtifactsCompilerInstance(context);
}
public boolean validateConfiguration(final CompileScope scope) {
return true;
}
@NotNull
public String getDescription() {
return "Artifacts Packaging Compiler";
}
public static Set<Artifact> getAffectedArtifacts(final CompileContext compileContext) {
return compileContext.getUserData(AFFECTED_ARTIFACTS);
}
@Nullable
public static Set<String> getWrittenPaths(@NotNull CompileContext context) {
return context.getUserData(WRITTEN_PATHS_KEY);
}
}
@@ -0,0 +1,389 @@
/*
* 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.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.packagingCompiler.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.compiler.make.BuildParticipant;
import com.intellij.openapi.compiler.make.BuildParticipantProvider;
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.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.artifacts.ArtifactManager;
import com.intellij.packaging.artifacts.ArtifactProperties;
import com.intellij.packaging.artifacts.ArtifactPropertiesProvider;
import com.intellij.packaging.elements.CompositePackagingElement;
import com.intellij.packaging.elements.PackagingElementResolvingContext;
import com.intellij.packaging.impl.artifacts.ArtifactValidationUtil;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CaseInsensitiveStringHashingStrategy;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.*;
/**
* @author nik
*/
public class ArtifactsCompilerInstance extends CompilerInstance<ArtifactBuildTarget, ArtifactCompilerCompileItem,
String, ArtifactPackagingItemOutputState> {
private static final Logger LOG = Logger.getInstance("#com.intellij.packaging.impl.compiler.ArtifactsCompilerInstance");
private ArtifactsProcessingItemsBuilderContext myBuilderContext;
public ArtifactsCompilerInstance(CompileContext context) {
super(context);
}
@NotNull
@Override
public List<ArtifactBuildTarget> getAllTargets() {
return getArtifactTargets(false);
}
@NotNull
@Override
public List<ArtifactBuildTarget> getSelectedTargets() {
return getArtifactTargets(true);
}
private List<ArtifactBuildTarget> getArtifactTargets(final boolean selectedOnly) {
final List<ArtifactBuildTarget> targets = new ArrayList<ArtifactBuildTarget>();
new ReadAction() {
protected void run(final Result result) {
final Set<Artifact> artifacts;
if (selectedOnly) {
artifacts = ArtifactCompileScope.getArtifactsToBuild(getProject(), myContext.getCompileScope());
}
else {
artifacts = new HashSet<Artifact>(Arrays.asList(ArtifactManager.getInstance(getProject()).getArtifacts()));
}
List<Artifact> additionalArtifacts = new ArrayList<Artifact>();
for (BuildParticipantProvider provider : BuildParticipantProvider.EXTENSION_POINT_NAME.getExtensions()) {
for (Module module : ModuleManager.getInstance(getProject()).getModules()) {
final Collection<? extends BuildParticipant> participants = provider.getParticipants(module);
for (BuildParticipant participant : participants) {
ContainerUtil.addIfNotNull(participant.createArtifact(myContext), additionalArtifacts);
}
}
}
if (LOG.isDebugEnabled() && !additionalArtifacts.isEmpty()) {
LOG.debug("additional artifacts to build: " + additionalArtifacts);
}
artifacts.addAll(additionalArtifacts);
for (Artifact artifact : artifacts) {
targets.add(new ArtifactBuildTarget(artifact));
}
if (selectedOnly) {
myContext.putUserData(ArtifactsCompiler.AFFECTED_ARTIFACTS, artifacts);
}
}
}.execute();
return targets;
}
@Override
public void processObsoleteTarget(@NotNull String targetId, @NotNull List<Pair<String, ArtifactPackagingItemOutputState>> obsoleteItems) {
deleteFiles(obsoleteItems, Collections.<Pair<ArtifactCompilerCompileItem, ArtifactPackagingItemOutputState>>emptyList());
}
@NotNull
@Override
public List<ArtifactCompilerCompileItem> getItems(@NotNull ArtifactBuildTarget target) {
myBuilderContext = new ArtifactsProcessingItemsBuilderContext(myContext);
final Artifact artifact = target.getArtifact();
final Set<Artifact> selfIncludingArtifacts = new ReadAction<Set<Artifact>>() {
protected void run(final Result<Set<Artifact>> result) {
result.setResult(ArtifactValidationUtil.getInstance(getProject()).getSelfIncludingArtifacts());
}
}.execute().getResultObject();
if (selfIncludingArtifacts.contains(artifact)) {
myContext.addMessage(CompilerMessageCategory.ERROR, "Artifact '" + artifact.getName() + "' includes itself in the output layout", null, -1, -1);
return Collections.emptyList();
}
final String outputPath = artifact.getOutputPath();
if (outputPath == null || outputPath.length() == 0) {
myContext.addMessage(CompilerMessageCategory.ERROR, "Cannot build '" + artifact.getName() + "' artifact: output path is not specified",
null, -1, -1);
return Collections.emptyList();
}
new ReadAction() {
protected void run(final Result result) {
collectItems(artifact, outputPath);
}
}.execute();
return new ArrayList<ArtifactCompilerCompileItem>(myBuilderContext.getProcessingItems());
}
private void collectItems(@NotNull Artifact artifact, @NotNull String outputPath) {
final CompositePackagingElement<?> rootElement = artifact.getRootElement();
final VirtualFile outputFile = LocalFileSystem.getInstance().findFileByPath(outputPath);
final CopyToDirectoryInstructionCreator instructionCreator = new CopyToDirectoryInstructionCreator(myBuilderContext, outputPath, outputFile);
final PackagingElementResolvingContext resolvingContext = ArtifactManager.getInstance(getProject()).getResolvingContext();
rootElement.computeIncrementalCompilerInstructions(instructionCreator, resolvingContext, myBuilderContext, artifact.getArtifactType());
}
private boolean doBuild(final List<Pair<ArtifactCompilerCompileItem, ArtifactPackagingItemOutputState>> changedItems,
final Set<ArtifactCompilerCompileItem> processedItems,
final Set<String> writtenPaths, final Set<String> deletedJars) {
final boolean testMode = ApplicationManager.getApplication().isUnitTestMode();
final DeploymentUtil deploymentUtil = DeploymentUtil.getInstance();
final FileFilter fileFilter = new IgnoredFileFilter();
final Set<JarInfo> changedJars = new THashSet<JarInfo>();
for (String deletedJar : deletedJars) {
ContainerUtil.addIfNotNull(myBuilderContext.getJarInfo(deletedJar), changedJars);
}
try {
onBuildStartedOrFinished(false);
if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
return false;
}
int i = 0;
for (final Pair<ArtifactCompilerCompileItem, ArtifactPackagingItemOutputState> item : changedItems) {
final ArtifactCompilerCompileItem sourceItem = item.getFirst();
myContext.getProgressIndicator().checkCanceled();
final Ref<IOException> exception = Ref.create(null);
new ReadAction() {
protected void run(final Result result) {
final File fromFile = VfsUtil.virtualToIoFile(sourceItem.getFile());
for (DestinationInfo destination : sourceItem.getDestinations()) {
if (destination instanceof ExplodedDestinationInfo) {
final ExplodedDestinationInfo explodedDestination = (ExplodedDestinationInfo)destination;
File toFile = new File(FileUtil.toSystemDependentName(explodedDestination.getOutputPath()));
if (fromFile.exists()) {
try {
deploymentUtil.copyFile(fromFile, toFile, myContext, writtenPaths, fileFilter);
}
catch (IOException e) {
exception.set(e);
return;
}
}
}
else {
changedJars.add(((JarDestinationInfo)destination).getJarInfo());
}
}
}
}.execute();
if (exception.get() != null) {
throw exception.get();
}
myContext.getProgressIndicator().setFraction(++i * 1.0 / changedItems.size());
processedItems.add(sourceItem);
if (testMode) {
CompilerManagerImpl.addRecompiledPath(FileUtil.toSystemDependentName(sourceItem.getFile().getPath()));
}
}
JarsBuilder builder = new JarsBuilder(changedJars, fileFilter, myContext);
final boolean processed = builder.buildJars(writtenPaths);
if (!processed) {
return false;
}
Set<VirtualFile> recompiledSources = new HashSet<VirtualFile>();
for (JarInfo info : builder.getJarsToBuild()) {
for (Pair<String, VirtualFile> pair : info.getPackedFiles()) {
recompiledSources.add(pair.getSecond());
}
}
for (VirtualFile source : recompiledSources) {
ArtifactCompilerCompileItem item = myBuilderContext.getItemBySource(source);
LOG.assertTrue(item != null, source);
processedItems.add(item);
if (testMode) {
CompilerManagerImpl.addRecompiledPath(FileUtil.toSystemDependentName(item.getFile().getPath()));
}
}
onBuildStartedOrFinished(true);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Exception e) {
LOG.info(e);
myContext.addMessage(CompilerMessageCategory.ERROR, e.getLocalizedMessage(), null, -1, -1);
return false;
}
return true;
}
private void onBuildStartedOrFinished(final boolean finished) throws Exception {
final Set<Artifact> artifacts = myContext.getUserData(ArtifactsCompiler.AFFECTED_ARTIFACTS);
if (artifacts != null) {
for (Artifact artifact : artifacts) {
for (ArtifactPropertiesProvider provider : artifact.getPropertiesProviders()) {
final ArtifactProperties<?> properties = artifact.getProperties(provider);
if (finished) {
properties.onBuildFinished(artifact, myContext);
}
else {
properties.onBuildStarted(artifact, myContext);
}
}
}
}
}
private static THashSet<String> createPathsHashSet() {
return SystemInfo.isFileSystemCaseSensitive
? new THashSet<String>()
: new THashSet<String>(CaseInsensitiveStringHashingStrategy.INSTANCE);
}
@Override
public void processItems(@NotNull ArtifactBuildTarget target, @NotNull final List<Pair<ArtifactCompilerCompileItem, ArtifactPackagingItemOutputState>> changedItems,
@NotNull List<Pair<String, ArtifactPackagingItemOutputState>> obsoleteItems,
@NotNull final OutputConsumer<ArtifactCompilerCompileItem> consumer) {
final THashSet<String> deletedJars = deleteFiles(obsoleteItems, changedItems);
final Set<String> writtenPaths = createPathsHashSet();
final Ref<Boolean> built = Ref.create(false);
final Set<ArtifactCompilerCompileItem> processedItems = new HashSet<ArtifactCompilerCompileItem>();
CompilerUtil.runInContext(myContext, "Copying files", new ThrowableRunnable<RuntimeException>() {
public void run() throws RuntimeException {
built.set(doBuild(changedItems, processedItems, writtenPaths, deletedJars));
}
});
if (!built.get()) {
return;
}
myContext.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.updating.caches"));
myContext.getProgressIndicator().setText2("");
for (String path : writtenPaths) {
consumer.addFileToRefresh(new File(path));
}
for (ArtifactCompilerCompileItem item : processedItems) {
consumer.addProcessedItem(item);
}
myContext.putUserData(ArtifactsCompiler.WRITTEN_PATHS_KEY, writtenPaths);
}
private THashSet<String> deleteFiles(List<Pair<String, ArtifactPackagingItemOutputState>> obsoleteItems,
List<Pair<ArtifactCompilerCompileItem, ArtifactPackagingItemOutputState>> changedItems) {
myContext.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.deleting.outdated.files"));
final boolean testMode = ApplicationManager.getApplication().isUnitTestMode();
final THashSet<String> deletedJars = new THashSet<String>();
final THashSet<String> notDeletedJars = new THashSet<String>();
if (LOG.isDebugEnabled()) {
LOG.debug("Deleting outdated files...");
}
Set<String> pathToDelete = new THashSet<String>();
for (Pair<ArtifactCompilerCompileItem, ArtifactPackagingItemOutputState> item : changedItems) {
final ArtifactPackagingItemOutputState cached = item.getSecond();
if (cached != null) {
for (Pair<String, Long> destination : cached.myDestinations) {
pathToDelete.add(destination.getFirst());
}
}
}
for (Pair<ArtifactCompilerCompileItem, ArtifactPackagingItemOutputState> item : changedItems) {
for (DestinationInfo destination : item.getFirst().getDestinations()) {
pathToDelete.remove(destination.getOutputPath());
}
}
for (Pair<String, ArtifactPackagingItemOutputState> item : obsoleteItems) {
for (Pair<String, Long> destination : item.getSecond().myDestinations) {
pathToDelete.add(destination.getFirst());
}
}
int notDeletedFilesCount = 0;
List<File> filesToRefresh = new ArrayList<File>();
for (String fullPath : pathToDelete) {
int end = fullPath.indexOf(JarFileSystem.JAR_SEPARATOR);
boolean isJar = end != -1;
String filePath = isJar ? fullPath.substring(0, end) : fullPath;
boolean deleted = false;
if (isJar) {
if (notDeletedJars.contains(filePath)) {
continue;
}
deleted = deletedJars.contains(filePath);
}
File file = new File(FileUtil.toSystemDependentName(filePath));
if (!deleted) {
filesToRefresh.add(file);
deleted = FileUtil.delete(file);
}
if (deleted) {
if (isJar) {
deletedJars.add(filePath);
}
if (testMode) {
CompilerManagerImpl.addDeletedPath(file.getAbsolutePath());
}
}
else {
if (isJar) {
notDeletedJars.add(filePath);
}
if (notDeletedFilesCount++ > 50) {
myContext.addMessage(CompilerMessageCategory.WARNING, "Deletion of outdated files stopped because too many files cannot be deleted", null, -1, -1);
break;
}
myContext.addMessage(CompilerMessageCategory.WARNING, "Cannot delete file '" + filePath + "'", null, -1, -1);
if (LOG.isDebugEnabled()) {
LOG.debug("Cannot delete file " + file);
}
}
}
CompilerUtil.refreshIOFiles(filesToRefresh);
return deletedJars;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -32,15 +32,14 @@ import java.util.Map;
* @author nik
*/
public class ArtifactsProcessingItemsBuilderContext implements ArtifactIncrementalCompilerContext {
private boolean myCollectingEnabledItems;
protected final Map<VirtualFile, ArtifactPackagingProcessingItem> myItemsBySource;
protected final Map<VirtualFile, ArtifactCompilerCompileItem> myItemsBySource;
private final Map<String, VirtualFile> mySourceByOutput;
private final Map<String, JarInfo> myJarByPath;
private final CompileContext myCompileContext;
public ArtifactsProcessingItemsBuilderContext(CompileContext compileContext) {
myCompileContext = compileContext;
myItemsBySource = new HashMap<VirtualFile, ArtifactPackagingProcessingItem>();
myItemsBySource = new HashMap<VirtualFile, ArtifactCompilerCompileItem>();
mySourceByOutput = new HashMap<String, VirtualFile>();
myJarByPath = new HashMap<String, JarInfo>();
}
@@ -51,19 +50,14 @@ public class ArtifactsProcessingItemsBuilderContext implements ArtifactIncrement
}
if (checkOutputPath(destinationInfo.getOutputPath(), sourceFile)) {
getOrCreateProcessingItem(sourceFile).addDestination(destinationInfo, myCollectingEnabledItems);
getOrCreateProcessingItem(sourceFile).addDestination(destinationInfo);
return true;
}
return false;
}
public ArtifactPackagingProcessingItem[] getProcessingItems() {
final Collection<ArtifactPackagingProcessingItem> processingItems = myItemsBySource.values();
return processingItems.toArray(new ArtifactPackagingProcessingItem[processingItems.size()]);
}
public void setCollectingEnabledItems(boolean collectingEnabledItems) {
myCollectingEnabledItems = collectingEnabledItems;
public Collection<ArtifactCompilerCompileItem> getProcessingItems() {
return myItemsBySource.values();
}
public boolean checkOutputPath(final String outputPath, final VirtualFile sourceFile) {
@@ -76,7 +70,7 @@ public class ArtifactsProcessingItemsBuilderContext implements ArtifactIncrement
return false;
}
public ArtifactPackagingProcessingItem getItemBySource(VirtualFile source) {
public ArtifactCompilerCompileItem getItemBySource(VirtualFile source) {
return myItemsBySource.get(source);
}
@@ -102,10 +96,10 @@ public class ArtifactsProcessingItemsBuilderContext implements ArtifactIncrement
return myCompileContext;
}
public ArtifactPackagingProcessingItem getOrCreateProcessingItem(VirtualFile sourceFile) {
ArtifactPackagingProcessingItem item = myItemsBySource.get(sourceFile);
public ArtifactCompilerCompileItem getOrCreateProcessingItem(VirtualFile sourceFile) {
ArtifactCompilerCompileItem item = myItemsBySource.get(sourceFile);
if (item == null) {
item = new ArtifactPackagingProcessingItem(sourceFile);
item = new ArtifactCompilerCompileItem(sourceFile);
myItemsBySource.put(sourceFile, item);
}
return item;
@@ -29,7 +29,8 @@ public class CopyToDirectoryInstructionCreator extends IncrementalCompilerInstru
private final String myOutputPath;
private final @Nullable VirtualFile myOutputFile;
public CopyToDirectoryInstructionCreator(ArtifactsProcessingItemsBuilderContext context, String outputPath, @Nullable VirtualFile outputFile) {
public CopyToDirectoryInstructionCreator(ArtifactsProcessingItemsBuilderContext context, String outputPath,
@Nullable VirtualFile outputFile) {
super(context);
myOutputPath = outputPath;
myOutputFile = outputFile;
@@ -1,583 +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.packaging.impl.compiler;
import com.intellij.compiler.CompilerManagerImpl;
import com.intellij.compiler.impl.CompilerCacheManager;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.FileProcessingCompilerStateCache;
import com.intellij.compiler.impl.packagingCompiler.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.compiler.make.BuildParticipant;
import com.intellij.openapi.compiler.make.BuildParticipantProvider;
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.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.artifacts.ArtifactManager;
import com.intellij.packaging.artifacts.ArtifactProperties;
import com.intellij.packaging.artifacts.ArtifactPropertiesProvider;
import com.intellij.packaging.elements.CompositePackagingElement;
import com.intellij.packaging.elements.PackagingElementResolvingContext;
import com.intellij.packaging.impl.artifacts.ArtifactValidationUtil;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CaseInsensitiveStringHashingStrategy;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.*;
/**
* @author nik
*/
public class IncrementalArtifactsCompiler implements PackagingCompiler {
private static final Logger LOG = Logger.getInstance("#com.intellij.packaging.impl.compiler.IncrementalArtifactsCompiler");
private static final Key<Set<String>> WRITTEN_PATHS_KEY = Key.create("artifacts_written_paths");
private static final Key<List<String>> FILES_TO_DELETE_KEY = Key.create("artifacts_files_to_delete");
private static final Key<Set<Artifact>> AFFECTED_ARTIFACTS = Key.create("affected_artifacts");
private static final Key<ArtifactsProcessingItemsBuilderContext> BUILDER_CONTEXT_KEY = Key.create("artifacts_builder_context");
@Nullable private PackagingCompilerCache myOutputItemsCache;
@Nullable
public static IncrementalArtifactsCompiler getInstance(@NotNull Project project) {
final IncrementalArtifactsCompiler[] compilers = CompilerManager.getInstance(project).getCompilers(IncrementalArtifactsCompiler.class);
return compilers.length == 1 ? compilers[0] : null;
}
private static ArtifactPackagingProcessingItem[] collectItems(ArtifactsProcessingItemsBuilderContext builderContext, final Project project) {
final CompileContext context = builderContext.getCompileContext();
final Set<Artifact> artifactsToBuild = ArtifactCompileScope.getArtifactsToBuild(project, context.getCompileScope());
if (LOG.isDebugEnabled()) {
LOG.debug("artifacts to build: " + artifactsToBuild);
}
List<Artifact> additionalArtifacts = new ArrayList<Artifact>();
for (BuildParticipantProvider provider : BuildParticipantProvider.EXTENSION_POINT_NAME.getExtensions()) {
for (Module module : ModuleManager.getInstance(project).getModules()) {
final Collection<? extends BuildParticipant> participants = provider.getParticipants(module);
for (BuildParticipant participant : participants) {
ContainerUtil.addIfNotNull(participant.createArtifact(context), additionalArtifacts);
}
}
}
if (LOG.isDebugEnabled() && !additionalArtifacts.isEmpty()) {
LOG.debug("additional artifacts to build: " + additionalArtifacts);
}
artifactsToBuild.addAll(additionalArtifacts);
final List<Artifact> allArtifacts = new ArrayList<Artifact>(Arrays.asList(ArtifactManager.getInstance(project).getArtifacts()));
allArtifacts.addAll(additionalArtifacts);
for (Artifact artifact : allArtifacts) {
final String outputPath = artifact.getOutputPath();
if (outputPath != null && outputPath.length() != 0) {
collectItems(builderContext, artifact, outputPath, project, artifactsToBuild.contains(artifact));
}
else if (artifactsToBuild.contains(artifact)) {
context.addMessage(CompilerMessageCategory.ERROR, "Cannot build '" + artifact.getName() + "' artifact: output path is not specified",
null, -1, -1);
}
}
context.putUserData(AFFECTED_ARTIFACTS, artifactsToBuild);
return builderContext.getProcessingItems();
}
@NotNull
public ProcessingItem[] getProcessingItems(final CompileContext context) {
return new ReadAction<ProcessingItem[]>() {
protected void run(final Result<ProcessingItem[]> result) {
final Project project = context.getProject();
final Set<Artifact> selfIncludingArtifacts = ArtifactValidationUtil.getInstance(project).getSelfIncludingArtifacts();
if (!selfIncludingArtifacts.isEmpty()) {
LOG.info("Self including artifacts: " + selfIncludingArtifacts);
if (!ArtifactCompileScope.getArtifactsToBuild(project, context.getCompileScope()).isEmpty()) {
for (Artifact artifact : selfIncludingArtifacts) {
context.addMessage(CompilerMessageCategory.ERROR, "Artifact '" + artifact.getName() + "' includes itself in the output layout", null, -1, -1);
}
}
result.setResult(ProcessingItem.EMPTY_ARRAY);
return;
}
ArtifactsProcessingItemsBuilderContext builderContext = new ArtifactsProcessingItemsBuilderContext(context);
context.putUserData(BUILDER_CONTEXT_KEY, builderContext);
ArtifactPackagingProcessingItem[] allProcessingItems = collectItems(builderContext, project);
if (LOG.isDebugEnabled()) {
int num = Math.min(5000, allProcessingItems.length);
LOG.debug("All files (" + num + " of " + allProcessingItems.length + "):");
for (int i = 0; i < num; i++) {
LOG.debug(allProcessingItems[i].getFile().getPath());
}
}
try {
final FileProcessingCompilerStateCache cache =
CompilerCacheManager.getInstance(project).getFileProcessingCompilerCache(IncrementalArtifactsCompiler.this);
for (ArtifactPackagingProcessingItem item : allProcessingItems) {
item.init(cache);
}
}
catch (IOException e) {
context.requestRebuildNextTime(e.getMessage());
context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, -1, -1);
result.setResult(ProcessingItem.EMPTY_ARRAY);
LOG.info(e);
return;
}
boolean hasFilesToDelete = collectFilesToDelete(context, builderContext.getProcessingItems());
if (hasFilesToDelete) {
MockProcessingItem mockItem = new MockProcessingItem(new LightVirtualFile("239239293"));
result.setResult(ArrayUtil.append(allProcessingItems, mockItem, ProcessingItem.class));
}
else {
result.setResult(allProcessingItems);
}
}
}.execute().getResultObject();
}
private static void collectItems(@NotNull ArtifactsProcessingItemsBuilderContext builderContext,
@NotNull Artifact artifact,
@NotNull String outputPath,
final Project project, boolean enable) {
final CompositePackagingElement<?> rootElement = artifact.getRootElement();
final VirtualFile outputFile = LocalFileSystem.getInstance().findFileByPath(outputPath);
final CopyToDirectoryInstructionCreator instructionCreator =
new CopyToDirectoryInstructionCreator(builderContext, outputPath, outputFile);
final PackagingElementResolvingContext resolvingContext = ArtifactManager.getInstance(project).getResolvingContext();
builderContext.setCollectingEnabledItems(enable);
rootElement.computeIncrementalCompilerInstructions(instructionCreator, resolvingContext, builderContext, artifact.getArtifactType());
}
public ProcessingItem[] process(final CompileContext context, final ProcessingItem[] items) {
final Set<String> deletedJars = deleteOutdatedFiles(context);
final List<ArtifactPackagingProcessingItem> processedItems = new ArrayList<ArtifactPackagingProcessingItem>();
final Set<String> writtenPaths = createPathsHashSet();
final Ref<Boolean> built = Ref.create(false);
CompilerUtil.runInContext(context, "Copying files", new ThrowableRunnable<RuntimeException>() {
public void run() throws RuntimeException {
built.set(doBuild(context, items, processedItems, writtenPaths, deletedJars));
}
});
if (!built.get()) {
return ProcessingItem.EMPTY_ARRAY;
}
context.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.updating.caches"));
context.getProgressIndicator().setText2("");
refreshOutputFiles(writtenPaths);
new ReadAction() {
protected void run(final Result result) {
processDestinations(processedItems);
}
}.execute();
removeInvalidItems(processedItems);
updateOutputCache(context.getProject(), processedItems);
context.putUserData(WRITTEN_PATHS_KEY, writtenPaths);
return processedItems.toArray(new ProcessingItem[processedItems.size()]);
}
private static boolean doBuild(final CompileContext context,
final ProcessingItem[] items,
final List<ArtifactPackagingProcessingItem> processedItems,
final Set<String> writtenPaths,
final Set<String> deletedJars) {
final boolean testMode = ApplicationManager.getApplication().isUnitTestMode();
if (LOG.isDebugEnabled()) {
int num = Math.min(200, items.length);
LOG.debug("Files to process (" + num + " of " + items.length + "):");
for (int i = 0; i < num; i++) {
LOG.debug(items[i].getFile().getPath());
}
}
final DeploymentUtil deploymentUtil = DeploymentUtil.getInstance();
final FileFilter fileFilter = new IgnoredFileFilter();
final ArtifactsProcessingItemsBuilderContext builderContext = context.getUserData(BUILDER_CONTEXT_KEY);
final Set<JarInfo> changedJars = new THashSet<JarInfo>();
for (String deletedJar : deletedJars) {
ContainerUtil.addIfNotNull(builderContext.getJarInfo(deletedJar), changedJars);
}
try {
onBuildStartedOrFinished(builderContext, false);
if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
return false;
}
int i = 0;
for (final ProcessingItem item0 : items) {
if (item0 instanceof MockProcessingItem) continue;
final ArtifactPackagingProcessingItem item = (ArtifactPackagingProcessingItem)item0;
context.getProgressIndicator().checkCanceled();
final Ref<IOException> exception = Ref.create(null);
new ReadAction() {
protected void run(final Result result) {
final File fromFile = VfsUtil.virtualToIoFile(item.getFile());
for (DestinationInfo destination : item.getEnabledDestinations()) {
if (destination instanceof ExplodedDestinationInfo) {
final ExplodedDestinationInfo explodedDestination = (ExplodedDestinationInfo)destination;
File toFile = new File(FileUtil.toSystemDependentName(explodedDestination.getOutputPath()));
if (fromFile.exists()) {
try {
deploymentUtil.copyFile(fromFile, toFile, context, writtenPaths, fileFilter);
}
catch (IOException e) {
exception.set(e);
return;
}
}
}
else {
changedJars.add(((JarDestinationInfo)destination).getJarInfo());
}
}
}
}.execute();
if (exception.get() != null) {
throw exception.get();
}
context.getProgressIndicator().setFraction(++i * 1.0 / items.length);
processedItems.add(item);
if (testMode) {
CompilerManagerImpl.addRecompiledPath(FileUtil.toSystemDependentName(item.getFile().getPath()));
}
}
JarsBuilder builder = new JarsBuilder(changedJars, fileFilter, context);
final boolean processed = builder.buildJars(writtenPaths);
if (!processed) {
return false;
}
Set<VirtualFile> recompiledSources = new HashSet<VirtualFile>();
for (JarInfo info : builder.getJarsToBuild()) {
for (Pair<String, VirtualFile> pair : info.getPackedFiles()) {
recompiledSources.add(pair.getSecond());
}
}
for (ArtifactPackagingProcessingItem processedItem : processedItems) {
recompiledSources.remove(processedItem.getFile());
}
for (VirtualFile source : recompiledSources) {
ArtifactPackagingProcessingItem item = builderContext.getItemBySource(source);
LOG.assertTrue(item != null, source);
processedItems.add(item);
if (testMode) {
CompilerManagerImpl.addRecompiledPath(FileUtil.toSystemDependentName(item.getFile().getPath()));
}
}
onBuildStartedOrFinished(builderContext, true);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Exception e) {
LOG.info(e);
context.addMessage(CompilerMessageCategory.ERROR, e.getLocalizedMessage(), null, -1, -1);
return false;
}
return true;
}
public static Set<Artifact> getAffectedArtifacts(final CompileContext compileContext) {
return compileContext.getUserData(AFFECTED_ARTIFACTS);
}
@Nullable
public static Set<String> getWrittenPaths(@NotNull CompileContext context) {
return context.getUserData(WRITTEN_PATHS_KEY);
}
@NotNull
public String getDescription() {
return "Artifacts Packaging Compiler";
}
@NotNull
private PackagingCompilerCache getOutputItemsCache(final Project project) {
if (myOutputItemsCache == null) {
myOutputItemsCache = new PackagingCompilerCache(
CompilerPaths.getCompilerSystemDirectory(project).getPath() + File.separator + "incremental_artifacts_timestamp.dat");
}
return myOutputItemsCache;
}
public void processOutdatedItem(final CompileContext context, final String url, @Nullable final ValidityState state) {
}
private boolean collectFilesToDelete(final CompileContext context, final ArtifactPackagingProcessingItem[] allProcessingItems) {
List<String> filesToDelete = new ArrayList<String>();
Set<String> outputPaths = createPathsHashSet();
for (ArtifactPackagingProcessingItem item : allProcessingItems) {
for (Pair<DestinationInfo, Boolean> destinationInfo : item.getDestinations()) {
String outputPath = getOutputPathWithJarSeparator(destinationInfo.getFirst());
outputPaths.add(outputPath);
}
}
final Iterator<String> pathIterator = getOutputItemsCache(context.getProject()).getUrlsIterator();
while (pathIterator.hasNext()) {
String path = pathIterator.next();
if (!outputPaths.contains(path)) {
filesToDelete.add(path);
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Files to delete (" + filesToDelete.size() + "):");
for (String path : filesToDelete) {
LOG.debug(path);
}
}
if (filesToDelete.isEmpty()) {
return false;
}
context.putUserData(FILES_TO_DELETE_KEY, filesToDelete);
return true;
}
private static String getOutputPathWithJarSeparator(DestinationInfo destinationInfo) {
String outputPath = destinationInfo.getOutputFilePath();
if (destinationInfo instanceof JarDestinationInfo) {
final String fullOutputPath = destinationInfo.getOutputPath();
final String fileOutputPath = destinationInfo.getOutputFilePath();
if (fullOutputPath.startsWith(fileOutputPath)) {
outputPath += JarFileSystem.JAR_SEPARATOR + DeploymentUtil.trimForwardSlashes(fullOutputPath.substring(fileOutputPath.length()));
}
}
return outputPath;
}
private static void onBuildStartedOrFinished(ArtifactsProcessingItemsBuilderContext context, final boolean finished) throws Exception {
final CompileContext compileContext = context.getCompileContext();
final Set<Artifact> artifacts = getAffectedArtifacts(compileContext);
for (Artifact artifact : artifacts) {
for (ArtifactPropertiesProvider provider : artifact.getPropertiesProviders()) {
final ArtifactProperties<?> properties = artifact.getProperties(provider);
if (finished) {
properties.onBuildFinished(artifact, compileContext);
}
else {
properties.onBuildStarted(artifact, compileContext);
}
}
}
}
private static THashSet<String> createPathsHashSet() {
return SystemInfo.isFileSystemCaseSensitive
? new THashSet<String>()
: new THashSet<String>(CaseInsensitiveStringHashingStrategy.INSTANCE);
}
private static void removeInvalidItems(List<ArtifactPackagingProcessingItem> processedItems) {
Set<VirtualFile> files = new THashSet<VirtualFile>(processedItems.size());
for (ArtifactPackagingProcessingItem item : processedItems) {
files.add(item.getFile());
}
RefreshQueue.getInstance().refresh(false, false, null, VfsUtil.toVirtualFileArray(files));
final Iterator<ArtifactPackagingProcessingItem> iterator = processedItems.iterator();
while (iterator.hasNext()) {
ArtifactPackagingProcessingItem item = iterator.next();
final VirtualFile file = item.getFile();
if (!file.isValid()) {
iterator.remove();
}
}
}
private static void processDestinations(final List<ArtifactPackagingProcessingItem> items) {
for (ArtifactPackagingProcessingItem item : items) {
item.setProcessed();
}
}
private Set<String> deleteOutdatedFiles(final CompileContext context) {
context.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.deleting.outdated.files"));
final List<String> filesToDelete = context.getUserData(FILES_TO_DELETE_KEY);
final Set<String> deletedJars;
if (filesToDelete != null) {
deletedJars = deleteFiles(filesToDelete, context);
}
else {
deletedJars = Collections.emptySet();
}
context.getProgressIndicator().checkCanceled();
return deletedJars;
}
private Set<String> deleteFiles(final List<String> paths, CompileContext context) {
final Set<Artifact> artifactsToBuild = getAffectedArtifacts(context);
final boolean testMode = ApplicationManager.getApplication().isUnitTestMode();
final THashSet<String> deletedJars = new THashSet<String>();
final THashSet<String> notDeletedJars = new THashSet<String>();
if (LOG.isDebugEnabled()) {
LOG.debug("Deleting outdated files...");
}
int notDeletedFilesCount = 0;
final Artifact[] allArtifacts = ArtifactManager.getInstance(context.getProject()).getArtifacts();
List<File> filesToRefresh = new ArrayList<File>();
for (String fullPath : paths) {
boolean isUnderOutput = false;
boolean isInArtifactsToBuild = false;
for (Artifact artifact : allArtifacts) {
final String path = artifact.getOutputPath();
if (!StringUtil.isEmpty(path) && FileUtil.startsWith(fullPath, path)) {
isUnderOutput = true;
if (artifactsToBuild.contains(artifact)) {
isInArtifactsToBuild = true;
break;
}
}
}
if (isUnderOutput && !isInArtifactsToBuild) continue;
int end = fullPath.indexOf(JarFileSystem.JAR_SEPARATOR);
boolean isJar = end != -1;
String filePath = isJar ? fullPath.substring(0, end) : fullPath;
boolean deleted = false;
if (isJar) {
if (notDeletedJars.contains(filePath)) {
continue;
}
deleted = deletedJars.contains(filePath);
}
File file = new File(FileUtil.toSystemDependentName(filePath));
if (!deleted) {
filesToRefresh.add(file);
deleted = FileUtil.delete(file);
}
if (deleted) {
if (isJar) {
deletedJars.add(filePath);
}
if (testMode) {
CompilerManagerImpl.addDeletedPath(file.getAbsolutePath());
}
getOutputItemsCache(context.getProject()).remove(fullPath);
}
else {
if (isJar) {
notDeletedJars.add(filePath);
}
if (notDeletedFilesCount++ > 50) {
context.addMessage(CompilerMessageCategory.WARNING, "Deletion of outdated files stopped because too many files cannot be deleted", null, -1, -1);
break;
}
context.addMessage(CompilerMessageCategory.WARNING, "Cannot delete file '" + filePath + "'", null, -1, -1);
if (LOG.isDebugEnabled()) {
LOG.debug("Cannot delete file " + file);
}
}
}
CompilerUtil.refreshIOFiles(filesToRefresh);
return deletedJars;
}
private void updateOutputCache(final Project project, final List<ArtifactPackagingProcessingItem> processedItems) {
for (ArtifactPackagingProcessingItem processedItem : processedItems) {
for (DestinationInfo destinationInfo : processedItem.getEnabledDestinations()) {
final VirtualFile virtualFile = destinationInfo.getOutputFile();
if (virtualFile != null) {
final String path = getOutputPathWithJarSeparator(destinationInfo);
if (LOG.isDebugEnabled()) {
LOG.debug("update output cache: file " + path);
}
getOutputItemsCache(project).update(path, virtualFile.getTimeStamp());
}
}
}
saveCacheIfDirty(project);
}
private static void refreshOutputFiles(Set<String> writtenPaths) {
final ArrayList<File> filesToRefresh = new ArrayList<File>();
for (String path : writtenPaths) {
filesToRefresh.add(new File(path));
}
CompilerUtil.refreshIOFiles(filesToRefresh);
}
private void saveCacheIfDirty(final Project project) {
if (getOutputItemsCache(project).isDirty()) {
getOutputItemsCache(project).save();
}
}
public ValidityState createValidityState(final DataInput is) throws IOException {
return new ArtifactPackagingItemValidityState(is);
}
public boolean validateConfiguration(final CompileScope scope) {
return true;
}
private static class MockProcessingItem implements ProcessingItem {
private final VirtualFile myFile;
public MockProcessingItem(final VirtualFile file) {
myFile = file;
}
@NotNull
public VirtualFile getFile() {
return myFile;
}
@Nullable
public ValidityState getValidityState() {
return null;
}
}
}
@@ -30,8 +30,8 @@ public class PackIntoArchiveInstructionCreator extends IncrementalCompilerInstru
private final JarInfo myJarInfo;
private final String myPathInJar;
public PackIntoArchiveInstructionCreator(ArtifactsProcessingItemsBuilderContext context, JarInfo jarInfo, String pathInJar,
DestinationInfo jarDestination) {
public PackIntoArchiveInstructionCreator(ArtifactsProcessingItemsBuilderContext context, JarInfo jarInfo,
String pathInJar, DestinationInfo jarDestination) {
super(context);
myJarInfo = jarInfo;
myPathInJar = pathInJar;
@@ -55,7 +55,8 @@ public class PackIntoArchiveInstructionCreator extends IncrementalCompilerInstru
public IncrementalCompilerInstructionCreator archive(@NotNull String archiveFileName) {
final JarInfo jarInfo = new JarInfo();
if (!myContext.registerJarFile(jarInfo, myJarDestination.getOutputPath() + "/" + archiveFileName)) {
final String outputPath = myJarDestination.getOutputPath() + "/" + archiveFileName;
if (!myContext.registerJarFile(jarInfo, outputPath)) {
return new SkipAllInstructionCreator(myContext);
}
final JarDestinationInfo destination = new JarDestinationInfo(childPathInJar(archiveFileName), myJarInfo, myJarDestination);
@@ -249,13 +249,19 @@ public class ManifestFileUtil {
VirtualFile dir = files[0];
try {
if (!dir.getName().equals(MANIFEST_DIR_NAME)) {
VirtualFile newDir = dir.findChild(MANIFEST_DIR_NAME);
if (newDir == null) {
newDir = dir.createChildDirectory(this, MANIFEST_DIR_NAME);
}
dir = newDir;
dir = VfsUtil.createDirectoryIfMissing(dir, MANIFEST_DIR_NAME);
}
result.setResult(dir.createChildData(this, MANIFEST_FILE_NAME));
final VirtualFile file = dir.createChildData(this, MANIFEST_FILE_NAME);
final OutputStream output = file.getOutputStream(this);
try {
final Manifest manifest = new Manifest();
ManifestBuilder.setVersionAttribute(manifest.getMainAttributes());
manifest.write(output);
}
finally {
output.close();
}
result.setResult(file);
}
catch (IOException e) {
exc.set(e);
@@ -35,7 +35,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.packaging.artifacts.*;
import com.intellij.packaging.impl.compiler.ArtifactAwareCompiler;
import com.intellij.packaging.impl.compiler.ArtifactCompileScope;
import com.intellij.packaging.impl.compiler.IncrementalArtifactsCompiler;
import com.intellij.packaging.impl.compiler.ArtifactsCompiler;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
@@ -148,7 +148,7 @@ public class BuildArtifactsBeforeRunTaskProvider extends BeforeRunTaskProvider<B
};
final CompilerFilter compilerFilter = new CompilerFilter() {
public boolean acceptCompiler(Compiler compiler) {
return compiler instanceof IncrementalArtifactsCompiler
return compiler instanceof ArtifactsCompiler
|| compiler instanceof ArtifactAwareCompiler && ((ArtifactAwareCompiler)compiler).shouldRun(artifacts);
}
};
@@ -18,6 +18,8 @@ package com.intellij.lang.java.parser;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.lang.LighterASTNode;
import com.intellij.lang.PsiBuilder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
@@ -36,6 +38,8 @@ public class DeclarationParser {
FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE
}
private static final Logger LOG = Logger.getInstance("#com.intellij.lang.java.parser.DeclarationParser");
private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD);
private DeclarationParser() { }
@@ -48,10 +52,11 @@ public class DeclarationParser {
marker.drop();
builder.advanceLexer();
final PsiBuilder builderWrapper = braceMatchingBuilder(builder);
if (isEnum) {
parseEnumConstants(builder);
parseEnumConstants(builderWrapper);
}
parseClassBodyDeclarations(builder, isAnnotation);
parseClassBodyDeclarations(builderWrapper, isAnnotation);
expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
@@ -186,10 +191,11 @@ public class DeclarationParser {
final PsiBuilder.Marker declaration = builder.mark();
final PsiBuilder.Marker modList = parseModifierList(builder);
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
final PsiBuilder.Marker modList = modListInfo.first;
if (expect(builder, JavaTokenType.AT)) {
if (tokenType == JavaTokenType.INTERFACE_KEYWORD) {
if (builder.getTokenType() == JavaTokenType.INTERFACE_KEYWORD) {
return parseClassFromKeyword(builder, declaration, true);
}
else {
@@ -197,9 +203,8 @@ public class DeclarationParser {
return null;
}
}
else if (ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType)) {
else if (ElementType.CLASS_KEYWORD_BIT_SET.contains(builder.getTokenType())) {
final PsiBuilder.Marker root = parseClassFromKeyword(builder, declaration, false);
if (context == Context.FILE) {
// todo: append following declarations to root
boolean declarationsAfterEnd = false;
@@ -233,29 +238,113 @@ public class DeclarationParser {
}
if (context == Context.FILE) {
if (typeParams == null) {
error(builder, JavaErrorMessages.message("expected.class.or.interface"));
}
else {
typeParams.precede().errorBefore(JavaErrorMessages.message("expected.class.or.interface"), typeParams);
}
error(builder, JavaErrorMessages.message("expected.class.or.interface"), typeParams);
declaration.drop();
return modList;
}
// todo: implement
throw new UnsupportedOperationException(builder.toString() + context);
PsiBuilder.Marker type;
if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(builder.getTokenType())) {
type = parseTypeNotNull(builder);
}
else if (builder.getTokenType() == JavaTokenType.IDENTIFIER) {
final PsiBuilder.Marker idPos = builder.mark();
type = parseTypeNotNull(builder);
if (builder.getTokenType() == JavaTokenType.LPARENTH) { // constructor
if (context == Context.CODE_BLOCK) {
declaration.rollbackTo();
return null;
}
idPos.rollbackTo();
if (typeParams == null) {
emptyElement(builder, JavaElementType.TYPE_PARAMETER_LIST);
}
builder.advanceLexer();
if (builder.getTokenType() != JavaTokenType.LPARENTH) {
declaration.rollbackTo();
return null;
}
return parseMethodFromLeftParenth(builder, declaration, false);
}
idPos.drop();
}
else if (builder.getTokenType() == JavaTokenType.LBRACE) {
if (context == Context.CODE_BLOCK) {
error(builder, JavaErrorMessages.message("expected.identifier.or.type"), typeParams);
declaration.drop();
return modList;
}
final PsiBuilder.Marker codeBlock = StatementParser.parseCodeBlock(builder);
LOG.assertTrue(codeBlock != null);
if (typeParams != null) {
final PsiBuilder.Marker error = typeParams.precede();
error.errorBefore(JavaErrorMessages.message("unexpected.token"), codeBlock);
}
declaration.done(JavaElementType.CLASS_INITIALIZER);
return declaration;
}
else {
final PsiBuilder.Marker error;
if (typeParams != null) {
error = typeParams.precede();
}
else {
error = builder.mark();
}
error.error(JavaErrorMessages.message("expected.identifier.or.type"));
return modList;
}
if (!expect(builder, JavaTokenType.IDENTIFIER)) {
if (context == Context.CODE_BLOCK && modListInfo.second) {
declaration.rollbackTo();
return null;
}
else {
if (typeParams != null) {
typeParams.precede().errorBefore(JavaErrorMessages.message("unexpected.token"), type);
}
builder.error(JavaErrorMessages.message("expected.identifier"));
declaration.drop();
return modList;
}
}
if (builder.getTokenType() == JavaTokenType.LPARENTH) {
if (context == Context.CLASS || context == Context.ANNOTATION_INTERFACE) { // method
if (typeParams == null) {
emptyElement(type, JavaElementType.TYPE_PARAMETER_LIST);
}
return parseMethodFromLeftParenth(builder, declaration, (context == Context.ANNOTATION_INTERFACE));
}
}
if (typeParams != null) {
typeParams.precede().errorBefore(JavaErrorMessages.message("unexpected.token"), type);
}
return parseFieldOrLocalVariable(builder, declaration, context);
}
@NotNull
private static PsiBuilder.Marker parseModifierList(final PsiBuilder builder) {
private static PsiBuilder.Marker parseTypeNotNull(final PsiBuilder builder) {
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
assert typeInfo != null : builder.getOriginalText();
return typeInfo.marker;
}
@NotNull
private static Pair<PsiBuilder.Marker, Boolean> parseModifierList(final PsiBuilder builder) {
final PsiBuilder.Marker modList = builder.mark();
boolean isEmpty = true;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null) break;
if (ElementType.MODIFIER_BIT_SET.contains(tokenType)) {
builder.advanceLexer();
isEmpty = false;
}
else if (tokenType == JavaTokenType.AT) {
final PsiBuilder.Marker pos = builder.mark();
@@ -266,6 +355,7 @@ public class DeclarationParser {
break;
}
parseAnnotation(builder);
isEmpty = false;
}
else {
break;
@@ -273,7 +363,225 @@ public class DeclarationParser {
}
modList.done(JavaElementType.MODIFIER_LIST);
return modList;
return Pair.create(modList, isEmpty);
}
private static PsiBuilder.Marker parseMethodFromLeftParenth(final PsiBuilder builder, final PsiBuilder.Marker declaration,
final boolean anno) {
parseParameterList(builder);
eatBrackets(builder);
if (areTypeAnnotationsSupported(builder)) {
final PsiBuilder.Marker receiver = builder.mark();
final PsiBuilder.Marker annotations = parseAnnotations(builder);
if (annotations != null) {
receiver.done(JavaElementType.METHOD_RECEIVER);
}
else {
receiver.drop();
}
}
ReferenceParser.parseReferenceList(builder, JavaTokenType.THROWS_KEYWORD, JavaElementType.THROWS_LIST, JavaTokenType.COMMA);
if (anno && expect(builder, JavaTokenType.DEFAULT_KEYWORD)) {
parseAnnotationValue(builder);
}
final IElementType tokenType = builder.getTokenType();
if (tokenType == JavaTokenType.SEMICOLON) {
builder.advanceLexer();
}
else if (tokenType == JavaTokenType.LBRACE) {
StatementParser.parseCodeBlock(builder);
}
else {
error(builder, JavaErrorMessages.message("expected.lbrace.or.semicolon"));
// todo: special treatment - like in fields (DeclarationParserTest.testMultiLineUnclosed())
}
declaration.done(anno ? JavaElementType.ANNOTATION_METHOD : JavaElementType.METHOD);
return declaration;
}
@NotNull
private static PsiBuilder.Marker parseParameterList(final PsiBuilder builder) {
assert builder.getTokenType() == JavaTokenType.LPARENTH : builder.getTokenType();
final PsiBuilder.Marker paramList = builder.mark();
builder.advanceLexer();
PsiBuilder.Marker invalidElements = null;
boolean commaExpected = false;
int paramCount = 0;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null || tokenType == JavaTokenType.RPARENTH) {
boolean noLastParam = !commaExpected && paramCount > 0;
if (noLastParam) {
error(builder, JavaErrorMessages.message("expected.identifier.or.type"));
}
if (!expect(builder, JavaTokenType.RPARENTH)) {
if (!noLastParam) {
error(builder, JavaErrorMessages.message("expected.rparen"));
}
}
break;
}
if (commaExpected) {
if (builder.getTokenType() == JavaTokenType.COMMA) {
commaExpected = false;
if (invalidElements != null) {
invalidElements.error(JavaErrorMessages.message("expected.parameter"));
invalidElements = null;
}
builder.advanceLexer();
continue;
}
}
else {
final PsiBuilder.Marker param = parseParameter(builder, true);
if (param != null) {
commaExpected = true;
if (invalidElements != null) {
invalidElements.errorBefore(JavaErrorMessages.message("expected.comma"), param);
invalidElements = null;
}
paramCount++;
continue;
}
}
if (invalidElements == null) {
if (builder.getTokenType() == JavaTokenType.COMMA) {
error(builder, JavaErrorMessages.message("expected.parameter"));
builder.advanceLexer();
continue;
}
else {
invalidElements = builder.mark();
}
}
// adding a reference, not simple tokens allows "Browse .." to work well
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, true, false);
if (ref == null && builder.getTokenType() != null) {
builder.advanceLexer();
}
}
if (invalidElements != null) {
invalidElements.error(commaExpected ? JavaErrorMessages.message("expected.comma") : JavaErrorMessages.message("expected.parameter"));
}
paramList.done(JavaElementType.PARAMETER_LIST);
return paramList;
}
@Nullable
private static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis) {
final PsiBuilder.Marker param = builder.mark();
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
final PsiBuilder.Marker type = ellipsis ? ReferenceParser.parseTypeWithEllipsis(builder, true, true) :
ReferenceParser.parseType(builder, true, true);
if (type == null && modListInfo.second) {
param.rollbackTo();
return null;
}
if (type == null) {
error(builder, JavaErrorMessages.message("expected.type"));
emptyElement(builder, JavaElementType.TYPE);
}
if (expect(builder, JavaTokenType.IDENTIFIER)) {
eatBrackets(builder);
}
else {
error(builder, JavaErrorMessages.message("expected.identifier"));
}
param.done(JavaElementType.PARAMETER);
return param;
}
@Nullable
private static PsiBuilder.Marker parseFieldOrLocalVariable(final PsiBuilder builder, final PsiBuilder.Marker declaration,
final Context context) {
final IElementType varType;
if (context == Context.CLASS || context == Context.ANNOTATION_INTERFACE) {
varType = JavaElementType.FIELD;
}
else if (context == Context.CODE_BLOCK) {
varType = JavaElementType.LOCAL_VARIABLE;
}
else {
LOG.error("Unexpected context: " + context);
declaration.drop();
return null;
}
PsiBuilder.Marker variable = declaration;
boolean openMarker = true;
boolean eatSemicolon = true;
boolean expectSemicolon = true;
while (true) {
if (!eatBrackets(builder)) {
expectSemicolon = false;
}
if (expect(builder, JavaTokenType.EQ)) {
final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
if (expr == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
expectSemicolon = false;
break;
}
}
if (builder.getTokenType() == JavaTokenType.COMMA) {
variable.done(varType);
builder.advanceLexer();
variable = builder.mark();
}
else {
break;
}
if (!expect(builder, JavaTokenType.IDENTIFIER)) {
variable.drop();
error(builder, JavaErrorMessages.message("expected.identifier"));
openMarker = false;
eatSemicolon = false;
break;
}
}
if (eatSemicolon) {
if (!expect(builder, JavaTokenType.SEMICOLON) && expectSemicolon) {
error(builder, JavaErrorMessages.message("expected.semicolon"));
}
// todo: special treatment - see DeclarationParserTest.testMultiLineUnclosed()
}
if (openMarker) {
variable.done(varType);
}
return declaration;
}
private static boolean eatBrackets(final PsiBuilder builder) {
while (expect(builder, JavaTokenType.LBRACKET)) {
if (!expect(builder, JavaTokenType.RBRACKET)) {
error(builder, JavaErrorMessages.message("expected.rbracket"));
return false;
}
}
return true;
}
@Nullable
@@ -290,6 +598,7 @@ public class DeclarationParser {
@NotNull
private static PsiBuilder.Marker parseAnnotation(final PsiBuilder builder) {
assert builder.getTokenType() == JavaTokenType.AT : builder.getTokenType();
final PsiBuilder.Marker anno = builder.mark();
builder.advanceLexer();
@@ -408,6 +717,7 @@ public class DeclarationParser {
@NotNull
private static PsiBuilder.Marker parseAnnotationArrayInitializer(final PsiBuilder builder) {
assert builder.getTokenType() == JavaTokenType.LBRACE : builder.getTokenType();
final PsiBuilder.Marker annoArray = builder.mark();
builder.advanceLexer();
@@ -15,12 +15,16 @@
*/
package com.intellij.lang.java.parser;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiBuilderUtil;
import com.intellij.lang.*;
import com.intellij.openapi.util.Key;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.diff.FlyweightCapableTreeStructure;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class JavaParserUtil {
@@ -40,7 +44,7 @@ public class JavaParserUtil {
@NotNull
private static LanguageLevel getLanguageLevel(final PsiBuilder builder) {
final LanguageLevel level = builder.getUserData(LANG_LEVEL_KEY);
assert level != null;
assert level != null : builder;
return level;
}
@@ -49,6 +53,15 @@ public class JavaParserUtil {
builder.mark().error(message);
}
public static void error(final PsiBuilder builder, final String message, @Nullable final PsiBuilder.Marker before) {
if (before == null) {
error(builder, message);
}
else {
before.precede().errorBefore(message, before);
}
}
public static boolean expectOrError(final PsiBuilder builder, final IElementType expectedType, final String errorMessage) {
if (!PsiBuilderUtil.expect(builder, expectedType)) {
error(builder, errorMessage);
@@ -60,4 +73,106 @@ public class JavaParserUtil {
public static void emptyElement(final PsiBuilder builder, final IElementType type) {
builder.mark().done(type);
}
public static void emptyElement(final PsiBuilder.Marker before, final IElementType type) {
before.precede().doneBefore(type, before);
}
public static PsiBuilder braceMatchingBuilder(final PsiBuilder builder) {
return new PsiBuilderAdapter(builder) {
private int braceCount = 1;
private int lastOffset = -1;
@Override
public IElementType getTokenType() {
final IElementType tokenType = super.getTokenType();
if (getCurrentOffset() != lastOffset) {
if (tokenType == JavaTokenType.LBRACE) {
braceCount++;
}
else if (tokenType == JavaTokenType.RBRACE) {
braceCount--;
}
lastOffset = getCurrentOffset();
}
return (braceCount == 0 ? null : tokenType);
}
};
}
public static class PsiBuilderAdapter implements PsiBuilder {
protected final PsiBuilder myDelegate;
public PsiBuilderAdapter(final PsiBuilder delegate) {
myDelegate = delegate;
}
public CharSequence getOriginalText() {
return myDelegate.getOriginalText();
}
public void advanceLexer() {
myDelegate.advanceLexer();
}
@Nullable
public IElementType getTokenType() {
return myDelegate.getTokenType();
}
public void setTokenTypeRemapper(final ITokenTypeRemapper remapper) {
myDelegate.setTokenTypeRemapper(remapper);
}
@Nullable @NonNls
public String getTokenText() {
return myDelegate.getTokenText();
}
public int getCurrentOffset() {
return myDelegate.getCurrentOffset();
}
public Marker mark() {
return myDelegate.mark();
}
public void error(final String messageText) {
myDelegate.error(messageText);
}
public boolean eof() {
return myDelegate.eof();
}
public ASTNode getTreeBuilt() {
return myDelegate.getTreeBuilt();
}
public FlyweightCapableTreeStructure<LighterASTNode> getLightTree() {
return myDelegate.getLightTree();
}
public void setDebugMode(final boolean dbgMode) {
myDelegate.setDebugMode(dbgMode);
}
public void enforceCommentTokens(final TokenSet tokens) {
myDelegate.enforceCommentTokens(tokens);
}
@Nullable
public LighterASTNode getLatestDoneMarker() {
return myDelegate.getLatestDoneMarker();
}
@Nullable
public <T> T getUserData(@NotNull final Key<T> key) {
return myDelegate.getUserData(key);
}
public <T> void putUserData(@NotNull final Key<T> key, @Nullable final T value) {
myDelegate.putUserData(key, value);
}
}
}
@@ -53,6 +53,21 @@ public class ReferenceParser {
return typeInfo != null ? typeInfo.marker : null;
}
@Nullable
public static PsiBuilder.Marker parseTypeWithEllipsis(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard);
if (typeInfo == null) return null;
PsiBuilder.Marker type = typeInfo.marker;
if (builder.getTokenType() == JavaTokenType.ELLIPSIS) {
type = typeInfo.marker.precede();
builder.advanceLexer();
type.done(JavaElementType.TYPE);
}
return type;
}
@Nullable
private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
if (builder.getTokenType() == null) return null;
@@ -263,28 +278,26 @@ public class ReferenceParser {
return null;
}
if (expect(builder, JavaTokenType.EXTENDS_KEYWORD)) {
parseReferenceList(builder, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND);
}
else {
emptyElement(builder, JavaElementType.EXTENDS_BOUND_LIST);
}
parseReferenceList(builder, JavaTokenType.EXTENDS_KEYWORD, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND);
param.done(JavaElementType.TYPE_PARAMETER);
return param;
}
@NotNull
private static PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IElementType type, final IElementType delimiter) {
public static PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IElementType start,
final IElementType type, final IElementType delimiter) {
final PsiBuilder.Marker element = builder.mark();
while (true) {
final PsiBuilder.Marker classReference = parseJavaCodeReference(builder, true, true, true);
if (classReference == null) {
error(builder, JavaErrorMessages.message("expected.identifier"));
}
if (!expect(builder, delimiter)) {
break;
if (expect(builder, start)) {
while (true) {
final PsiBuilder.Marker classReference = parseJavaCodeReference(builder, true, true, true);
if (classReference == null) {
error(builder, JavaErrorMessages.message("expected.identifier"));
}
if (!expect(builder, delimiter)) {
break;
}
}
}
@@ -0,0 +1,44 @@
/*
* 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.lang.java.parser;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import org.jetbrains.annotations.Nullable;
public class StatementParser {
private StatementParser() { }
@Nullable
public static PsiBuilder.Marker parseCodeBlock(final PsiBuilder builder) {
if (builder.getTokenType() != JavaTokenType.LBRACE) return null;
final PsiBuilder.Marker codeBlock = builder.mark();
builder.advanceLexer();
// temp
if (builder.getTokenType() == JavaTokenType.RBRACE) {
builder.advanceLexer();
codeBlock.done(JavaElementType.CODE_BLOCK);
return codeBlock;
}
// todo: implement
throw new UnsupportedOperationException(builder.toString());
}
}
@@ -705,8 +705,8 @@ public class DeclarationParsing extends Parsing {
aClass.rawAddChildren(invalidElementsGroup);
while (true) {
IElementType tokenType = lexer.getTokenType();
if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.COMMA || tokenType == JavaTokenType.EXTENDS_KEYWORD || tokenType ==
JavaTokenType.IMPLEMENTS_KEYWORD) {
if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.COMMA || tokenType == JavaTokenType.EXTENDS_KEYWORD ||
tokenType == JavaTokenType.IMPLEMENTS_KEYWORD) {
invalidElementsGroup.rawAddChildren(ParseUtil.createTokenElement(lexer, myContext.getCharTable()));
}
else {
@@ -1086,7 +1086,7 @@ public class DeclarationParsing extends Parsing {
if (type == null) {
type = ASTFactory.composite(JavaElementType.TYPE);
param.rawAddChildren(Factory.createErrorElement("Parameter type missing"));
param.rawAddChildren(Factory.createErrorElement(JavaErrorMessages.message("expected.type")));
}
param.rawAddChildren(type);
@@ -111,6 +111,7 @@ public class StatementParsing extends Parsing {
return dummyRoot.getFirstChildNode();
}
@Nullable
public TreeElement parseCodeBlock(Lexer lexer, boolean deep) {
if (lexer.getTokenType() != JavaTokenType.LBRACE) return null;
Lexer badLexer = lexer instanceof StoppableLexerAdapter ? ((StoppableLexerAdapter)lexer).getDelegate() : lexer;
@@ -151,11 +152,10 @@ public class StatementParsing extends Parsing {
List<IElementType> list = new SmartList<IElementType>();
while (true) {
final IElementType type = lexer.getTokenType();
if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(type) || type == JavaTokenType.IDENTIFIER || ElementType.MODIFIER_BIT_SET.contains(type) ||
type == JavaTokenType.LT || type == JavaTokenType.GT || type == JavaTokenType.GTGT || type == JavaTokenType.GTGTGT || type ==
JavaTokenType.COMMA || type ==
JavaTokenType.DOT ||
type == JavaTokenType.EXTENDS_KEYWORD || type == JavaTokenType.IMPLEMENTS_KEYWORD) {
if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(type) || ElementType.MODIFIER_BIT_SET.contains(type) ||
type == JavaTokenType.IDENTIFIER || type == JavaTokenType.LT || type == JavaTokenType.GT ||
type == JavaTokenType.GTGT || type == JavaTokenType.GTGTGT || type == JavaTokenType.COMMA ||
type == JavaTokenType.DOT || type == JavaTokenType.EXTENDS_KEYWORD || type == JavaTokenType.IMPLEMENTS_KEYWORD) {
list.add(type);
lexer.advance();
} else {
@@ -93,7 +93,7 @@ public interface JavaElementType {
IElementType CLASS_OBJECT_ACCESS_EXPRESSION = new IJavaElementType("CLASS_OBJECT_ACCESS_EXPRESSION");
IElementType EMPTY_EXPRESSION = new IJavaElementType("EMPTY_EXPRESSION");
IElementType EXPRESSION_LIST = new IJavaElementType("EXPRESSION_LIST");
IElementType EXPRESSION_LIST = new IJavaElementType("EXPRESSION_LIST", true);
IElementType EMPTY_STATEMENT = new IJavaElementType("EMPTY_STATEMENT");
IElementType BLOCK_STATEMENT = new IJavaElementType("BLOCK_STATEMENT");
@@ -32,6 +32,7 @@ import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.util.classMembers.ClassMemberReferencesVisitor;
import com.intellij.refactoring.util.occurences.ExpressionOccurenceManager;
import com.intellij.refactoring.util.occurences.OccurenceManager;
@@ -85,6 +86,15 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
PsiExpression[] occurences,
PsiElement anchorElement,
PsiElement anchorElementIfAll) {
for (PsiExpression occurrence : occurences) {
if (RefactoringUtil.isAssignmentLHS(occurrence)) {
String message =
RefactoringBundle.getCannotRefactorMessage("Selected expression is used for write");
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, getHelpID());
highlightError(project, editor, occurrence);
return null;
}
}
PsiLocalVariable localVariable = null;
if (expr instanceof PsiReferenceExpression) {
PsiElement ref = ((PsiReferenceExpression)expr).resolve();
@@ -0,0 +1,33 @@
PsiJavaFile:CompletionHack0.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:s
PsiModifierList:
<empty list>
PsiErrorElement:Unexpected token
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:X
PsiIdentifier:X('X')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected identifier
PsiIdentifier:IntelliJIdeaRulezz('IntelliJIdeaRulezz')
PsiJavaToken:GT('>')
PsiWhiteSpace('\n ')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:s('s')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:""
PsiJavaToken:STRING_LITERAL('""')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,31 @@
PsiJavaFile:CompletionHack1.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:s
PsiModifierList:
<empty list>
PsiErrorElement:Unexpected token
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:X
PsiIdentifier:X('X')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
PsiWhiteSpace('\n ')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:s('s')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:""
PsiJavaToken:STRING_LITERAL('""')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,4 @@
PsiJavaFile:EmptyBody0.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,5 @@
PsiJavaFile:EmptyBody1.java
PsiJavaToken:LBRACE('{')
PsiErrorElement:'}' expected
<empty list>
PsiWhiteSpace(' ')
@@ -0,0 +1,6 @@
PsiJavaFile:EnumBody0.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,28 @@
PsiJavaFile:EnumBody1.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiEnumConstant:RED
PsiModifierList:
<empty list>
PsiIdentifier:RED('RED')
PsiExpressionList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiEnumConstant:GREEN
PsiModifierList:
<empty list>
PsiIdentifier:GREEN('GREEN')
PsiExpressionList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiEnumConstant:BLUE
PsiModifierList:
<empty list>
PsiIdentifier:BLUE('BLUE')
PsiExpressionList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,27 @@
PsiJavaFile:EnumBody2.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiEnumConstant:RED
PsiModifierList:
<empty list>
PsiIdentifier:RED('RED')
PsiExpressionList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiEnumConstant:GREEN
PsiModifierList:
<empty list>
PsiIdentifier:GREEN('GREEN')
PsiExpressionList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiEnumConstant:BLUE
PsiModifierList:
<empty list>
PsiIdentifier:BLUE('BLUE')
PsiExpressionList
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,28 @@
PsiJavaFile:EnumBody3.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiEnumConstant:RED
PsiModifierList:
<empty list>
PsiIdentifier:RED('RED')
PsiExpressionList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiEnumConstant:GREEN
PsiModifierList:
<empty list>
PsiIdentifier:GREEN('GREEN')
PsiExpressionList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiEnumConstant:BLUE
PsiModifierList:
<empty list>
PsiIdentifier:BLUE('BLUE')
PsiExpressionList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,37 @@
PsiJavaFile:EnumBody4.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiEnumConstant:RED
PsiModifierList:
<empty list>
PsiIdentifier:RED('RED')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:RPARENTH(')')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiEnumConstant:GREEN
PsiModifierList:
<empty list>
PsiIdentifier:GREEN('GREEN')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:RPARENTH(')')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiEnumConstant:BLUE
PsiModifierList:
<empty list>
PsiIdentifier:BLUE('BLUE')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiJavaToken:RPARENTH(')')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,22 @@
PsiJavaFile:EnumBody5.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiEnumConstant:A
PsiModifierList:@ANNOTATION
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:ANNOTATION
PsiIdentifier:ANNOTATION('ANNOTATION')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:A('A')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:10
PsiJavaToken:INTEGER_LITERAL('10')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,45 @@
PsiJavaFile:Errors.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiModifierList:public static
PsiKeyword:public('public')
PsiWhiteSpace(' ')
PsiKeyword:static('static')
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected token
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:error
PsiIdentifier:error('error')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
PsiWhiteSpace(' ')
PsiTypeElement:descr
PsiJavaCodeReferenceElement:descr
PsiIdentifier:descr('descr')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier expected
<empty list>
PsiErrorElement:Unexpected token
PsiJavaToken:EQ('=')
PsiJavaToken:STRING_LITERAL('"2"')
PsiJavaToken:GT('>')
PsiField:f1
PsiModifierList:protected
PsiKeyword:protected('protected')
PsiWhiteSpace(' ')
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:f1('f1')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,22 @@
PsiJavaFile:FieldMulti.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:field1
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:field1('field1')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiField:field2
PsiIdentifier:field2('field2')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,18 @@
PsiJavaFile:FieldSimple.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:field
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:field('field')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,91 @@
PsiJavaFile:GenericMethod.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:test
PsiModifierList:public static
PsiKeyword:public('public')
PsiWhiteSpace(' ')
PsiKeyword:static('static')
PsiWhiteSpace(' ')
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:E
PsiIdentifier:E('E')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiIdentifier:test('test')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n ')
PsiMethod:test1
PsiModifierList:
<empty list>
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:E
PsiIdentifier:E('E')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:test1('test1')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n ')
PsiMethod:test2
PsiModifierList:
<empty list>
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:E1
PsiIdentifier:E1('E1')
PsiWhiteSpace(' ')
PsiElement(EXTENDS_BOUND_LIST)
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiTypeParameter:E2
PsiIdentifier:E2('E2')
PsiWhiteSpace(' ')
PsiElement(EXTENDS_BOUND_LIST)
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:Runnable
PsiIdentifier:Runnable('Runnable')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:test2('test2')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,43 @@
PsiJavaFile:GenericMethodErrors.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiModifierList:
<empty list>
PsiErrorElement:Unexpected token
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:Error
PsiIdentifier:Error('Error')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
PsiWhiteSpace(' ')
PsiTypeElement:sss
PsiJavaCodeReferenceElement:sss
PsiIdentifier:sss('sss')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected token
PsiJavaToken:DIV('/')
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:test <error>
PsiIdentifier:test('test')
PsiWhiteSpace(' ')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:error
PsiJavaCodeReferenceElement:error
PsiIdentifier:error('error')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,24 @@
PsiJavaFile:MethodNormal0.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiWhiteSpace(' ')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,20 @@
PsiJavaFile:MethodNormal1.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,16 @@
PsiJavaFile:MissingInitializer.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:field
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:field('field')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiErrorElement:Expression expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,16 @@
PsiJavaFile:MissingInitializerExpression.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:field
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:field('field')
PsiJavaToken:EQ('=')
PsiErrorElement:Expression expected
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,23 @@
PsiJavaFile:MultiLineUnclosed.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace(' \n ')
PsiField:o
PsiModifierList:
<empty list>
PsiTypeElement:Object
PsiJavaCodeReferenceElement:Object
PsiIdentifier:Object('Object')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:o('o')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,21 @@
PsiJavaFile:Unclosed0.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,22 @@
PsiJavaFile:Unclosed1.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:(
PsiJavaToken:LPARENTH('(')
PsiErrorElement:')' expected
<empty list>
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,37 @@
PsiJavaFile:Unclosed2.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace('\n ')
PsiMethod:g
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:g('g')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,29 @@
PsiJavaFile:Unclosed3.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:(int a
PsiJavaToken:LPARENTH('(')
PsiParameter:a
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:a('a')
PsiErrorElement:')' expected
<empty list>
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,33 @@
PsiJavaFile:Unclosed4.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:(int a,,
PsiJavaToken:LPARENTH('(')
PsiParameter:a
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:a('a')
PsiJavaToken:COMMA(',')
PsiErrorElement:Parameter expected
<empty list>
PsiJavaToken:COMMA(',')
PsiErrorElement:Identifier or type expected
<empty list>
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,30 @@
PsiJavaFile:Unclosed5.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:(int a,)
PsiJavaToken:LPARENTH('(')
PsiParameter:a
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:a('a')
PsiJavaToken:COMMA(',')
PsiErrorElement:Identifier or type expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,15 @@
PsiJavaFile:UnclosedBracket.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:field
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:field('field')
PsiJavaToken:LBRACKET('[')
PsiErrorElement:']' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,15 @@
PsiJavaFile:UnclosedComma.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:field
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:field('field')
PsiJavaToken:COMMA(',')
PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,14 @@
PsiJavaFile:UnclosedSemicolon.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:field
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:field('field')
PsiErrorElement:';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,55 @@
PsiJavaFile:WildcardParsing.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:x
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:List<? extends B>
PsiJavaCodeReferenceElement:List<? extends B>
PsiIdentifier:List('List')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:? extends B
PsiJavaToken:QUEST('?')
PsiWhiteSpace(' ')
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiTypeElement:B
PsiJavaCodeReferenceElement:B
PsiIdentifier:B('B')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiIdentifier:x('x')
PsiParameterList:(Collection<? super B> x)
PsiJavaToken:LPARENTH('(')
PsiParameter:x
PsiModifierList:
<empty list>
PsiTypeElement:Collection<? super B>
PsiJavaCodeReferenceElement:Collection<? super B>
PsiIdentifier:Collection('Collection')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:? super B
PsiJavaToken:QUEST('?')
PsiWhiteSpace(' ')
PsiKeyword:super('super')
PsiWhiteSpace(' ')
PsiTypeElement:B
PsiJavaCodeReferenceElement:B
PsiIdentifier:B('B')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiIdentifier:x('x')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,11 @@
PsiJavaFile:Type5.java
PsiTypeElement:Object[]...
PsiTypeElement:Object[]
PsiTypeElement:Object
PsiJavaCodeReferenceElement:Object
PsiIdentifier:Object('Object')
PsiReferenceParameterList
<empty list>
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:ELLIPSIS('...')
@@ -4,9 +4,9 @@ PsiJavaFile:TypeParams5.java
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiWhiteSpace(' ')
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiElement(EXTENDS_BOUND_LIST)
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:X
PsiIdentifier:X('X')
PsiReferenceParameterList
@@ -4,9 +4,9 @@ PsiJavaFile:TypeParams7.java
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiWhiteSpace(' ')
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiElement(EXTENDS_BOUND_LIST)
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:X
PsiIdentifier:X('X')
PsiReferenceParameterList
@@ -0,0 +1,71 @@
/*
* 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.lang.java.parser.partial;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.java.parser.DeclarationParser;
import com.intellij.lang.java.parser.JavaParsingTestCase;
public class DeclarationParserTest extends JavaParsingTestCase {
public DeclarationParserTest() {
super("parser-partial/declarations");
}
public void testEmptyBody0() { doParserTest("{ }", false, false); }
public void testEmptyBody1() { doParserTest("{ ", false, false); }
public void testEnumBody0() { doParserTest("{ ; }", false, true); }
public void testEnumBody1() { doParserTest("{ RED, GREEN, BLUE; }", false, true); }
public void testEnumBody2() { doParserTest("{ RED, GREEN, BLUE }", false, true); }
public void testEnumBody3() { doParserTest("{ RED, GREEN, BLUE, }", false, true); }
public void testEnumBody4() { doParserTest("{ RED(0), GREEN(1), BLUE(2); }", false, true); }
public void testEnumBody5() { doParserTest("{ @ANNOTATION A(10) }", false, true); }
public void testFieldSimple() { doParserTest("{ int field = 0; }", false, false); }
public void testFieldMulti() { doParserTest("{ int field1 = 0, field2; }", false, false); }
public void testUnclosedBracket() { doParserTest("{ int field[ }", false, false); }
public void testMissingInitializer() { doParserTest("{ int field = }", false, false); }
public void testUnclosedComma() { doParserTest("{ int field, }", false, false); }
public void testUnclosedSemicolon() { doParserTest("{ int field }", false, false); }
public void testMissingInitializerExpression() { doParserTest("{ int field=; }", false, false); }
//public void testMultiLineUnclosed() { doParserTest("{ int \n Object o; }", false, false); } // todo: implement
//public void testMethodNormal0() { doParserTest("{ void f() { } }", false, false); } // todo: parse code block correctly
public void testMethodNormal1() { doParserTest("{ void f(); }", false, false); }
public void testUnclosed0() { doParserTest("{ void f() }", false, false); }
public void testUnclosed1() { doParserTest("{ void f( }", false, false); }
public void testUnclosed2() { doParserTest("{ void f()\n void g(); }", false, false); }
public void testUnclosed3() { doParserTest("{ void f(int a }", false, false); }
public void testUnclosed4() { doParserTest("{ void f(int a,, }", false, false); }
public void testUnclosed5() { doParserTest("{ void f(int a,); }", false, false); }
public void testGenericMethod() { doParserTest("{ public static <E> test();\n" +
" <E> void test1();\n" +
" <E1 extends Integer, E2 extends Runnable> String test2(); }", false, false); }
public void testGenericMethodErrors() { doParserTest("{ <Error sss /> test <error>(); }", false, false); }
public void testErrors() { doParserTest("{ public static <error descr=\"2\">protected int f1 = 0; }", false, false); }
public void testCompletionHack0() { doParserTest("{ <X IntelliJIdeaRulezz>\n String s = \"\"; }", false, false); }
public void testCompletionHack1() { doParserTest("{ <X\n String s = \"\"; }", false, false); }
public void testWildcardParsing() { doParserTest("{ List<? extends B> x(Collection<? super B> x); }", false, false); }
private void doParserTest(final String text, final boolean isAnnotation, final boolean isEnum) {
doParserTest(text, new Parser() {
public void parse(final PsiBuilder builder) {
DeclarationParser.parseClassBodyWithBraces(builder, isAnnotation, isEnum);
}
});
}
}
@@ -34,6 +34,7 @@ public class ReferenceParserTest extends JavaParsingTestCase {
public void testType2() { doTypeParserTest("int[]", false); }
public void testType3() { doTypeParserTest("int[][", false); }
public void testType4() { doTypeParserTest("Map<String,List<String>>", false); }
public void testType5() { doTypeParserTest("Object[]...", false); }
public void testTypeParams0() { doTypeParamsParserTest("<T>"); }
public void testTypeParams1() { doTypeParamsParserTest("<T, U>"); }
@@ -55,7 +56,7 @@ public class ReferenceParserTest extends JavaParsingTestCase {
private void doTypeParserTest(final String text, final boolean incomplete) {
doParserTest(text, new Parser() {
public void parse(final PsiBuilder builder) {
ReferenceParser.parseType(builder, incomplete, false);
ReferenceParser.parseTypeWithEllipsis(builder, incomplete, false);
}
});
}
@@ -0,0 +1,45 @@
/*
* 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.execution;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.process.ProcessHandler;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public class ExecutionAdapter implements ExecutionListener {
@Override
public void processStarting(@NotNull RunProfile runProfile) {
}
@Override
public void processNotStarted(@NotNull RunProfile runProfile) {
}
@Override
public void processStarted(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler) {
}
@Override
public void processTerminating(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler) {
}
@Override
public void processTerminated(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler) {
}
}
@@ -0,0 +1,38 @@
/*
* 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.execution;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.process.ProcessHandler;
import org.jetbrains.annotations.NotNull;
import java.util.EventListener;
/**
* @author nik
*/
public interface ExecutionListener extends EventListener {
void processStarting(@NotNull RunProfile runProfile);
void processNotStarted(@NotNull RunProfile runProfile);
void processStarted(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler);
void processTerminating(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler);
void processTerminated(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler);
}
@@ -18,10 +18,16 @@ package com.intellij.execution;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.RunContentManager;
import com.intellij.openapi.project.Project;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.NotNull;
public abstract class ExecutionManager {
public static final Topic<ExecutionListener> EXECUTION_TOPIC = new Topic<ExecutionListener>("configuration executed", ExecutionListener.class,
Topic.BroadcastDirection.TO_PARENT);
public static ExecutionManager getInstance(final Project project) {
return project.getComponent(ExecutionManager.class);
}
@@ -32,5 +38,6 @@ public abstract class ExecutionManager {
public abstract ProcessHandler[] getRunningProcesses();
public abstract void startRunProfile(@NotNull RunProfileStarter starter, @NotNull RunProfileState state,
@NotNull Project project, @NotNull Executor executor, @NotNull ExecutionEnvironment env);
}
@@ -0,0 +1,33 @@
/*
* 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.execution;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author nik
*/
public abstract class RunProfileStarter {
@Nullable
public abstract RunContentDescriptor execute(@NotNull Project project, @NotNull Executor executor, @NotNull RunProfileState state,
@Nullable RunContentDescriptor contentToReuse, @NotNull ExecutionEnvironment env) throws ExecutionException;
}
@@ -18,12 +18,9 @@ package com.intellij.execution.runners;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.history.LocalHistory;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.JDOMExternalizable;
@@ -67,51 +64,34 @@ public abstract class GenericProgramRunner<Settings extends JDOMExternalizable>
public void execute(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env, @Nullable final Callback callback)
throws ExecutionException {
final RunProfile profile = env.getRunProfile();
final Project project = env.getProject();
if (project == null) {
return;
}
final RunContentDescriptor reuseContent =
ExecutionManager.getInstance(project).getContentManager().getReuseContent(executor, env.getContentToReuse());
final RunProfileState state = env.getState(executor);
if (state == null) {
return;
}
Runnable startRunnable = new Runnable() {
public void run() {
try {
if (project.isDisposed()) return;
final RunContentDescriptor descriptor =
doExecute(project, executor, state, reuseContent, env);
if (callback != null) callback.processStarted(descriptor);
if (descriptor != null) {
ExecutionManager.getInstance(project).getContentManager().showRunContent(executor, descriptor);
final ProcessHandler processHandler = descriptor.getProcessHandler();
if (processHandler != null) processHandler.startNotify();
}
}
catch (ExecutionException e) {
ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), profile, e);
}
ExecutionManager.getInstance(project).startRunProfile(new RunProfileStarter() {
@Override
public RunContentDescriptor execute(@NotNull Project project,
@NotNull Executor executor,
@NotNull RunProfileState state,
@Nullable RunContentDescriptor contentToReuse,
@NotNull ExecutionEnvironment env) throws ExecutionException {
final RunContentDescriptor descriptor = doExecute(project, executor, state, contentToReuse, env);
if (callback != null) callback.processStarted(descriptor);
return descriptor;
}
};
if (ApplicationManager.getApplication().isUnitTestMode()) {
startRunnable.run();
}
else {
ExecutionManager.getInstance(project).compileAndRun(startRunnable, profile, state);
}
}, state, project, executor, env);
}
@Nullable
protected abstract RunContentDescriptor doExecute(final Project project, final Executor executor, final RunProfileState state,
final RunContentDescriptor contentToReuse,
final ExecutionEnvironment env) throws ExecutionException;
}
@@ -16,14 +16,16 @@
package com.intellij.execution.impl;
import com.intellij.execution.BeforeRunTask;
import com.intellij.execution.BeforeRunTaskProvider;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.*;
import com.intellij.execution.configurations.ConfigurationPerRunnerSettings;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ExecutionUtil;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunContentManager;
import com.intellij.execution.ui.RunContentManagerImpl;
@@ -64,7 +66,8 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom
public void projectClosed() {
}
public void initComponent() { }
public void initComponent() {
}
public void disposeComponent() {
}
@@ -94,53 +97,112 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom
public void compileAndRun(final Runnable startRunnable,
final RunProfile configuration,
final RunProfileState state) {
final Runnable antAwareRunnable = new Runnable() {
public void run() {
if (configuration instanceof RunConfiguration) {
final RunConfiguration runConfiguration = (RunConfiguration)configuration;
final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject);
if (configuration instanceof RunConfiguration) {
final RunConfiguration runConfiguration = (RunConfiguration)configuration;
final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject);
final Map<BeforeRunTaskProvider<BeforeRunTask>, BeforeRunTask> activeProviders = new LinkedHashMap<BeforeRunTaskProvider<BeforeRunTask>, BeforeRunTask>();
for (final BeforeRunTaskProvider<BeforeRunTask> provider : Extensions.getExtensions(BeforeRunTaskProvider.EXTENSION_POINT_NAME, myProject)) {
final BeforeRunTask task = runManager.getBeforeRunTask(runConfiguration, provider.getId());
if (task != null && task.isEnabled()) {
activeProviders.put(provider, task);
final Map<BeforeRunTaskProvider<BeforeRunTask>, BeforeRunTask> activeProviders = new LinkedHashMap<BeforeRunTaskProvider<BeforeRunTask>, BeforeRunTask>();
for (final BeforeRunTaskProvider<BeforeRunTask> provider : Extensions.getExtensions(BeforeRunTaskProvider.EXTENSION_POINT_NAME, myProject)) {
final BeforeRunTask task = runManager.getBeforeRunTask(runConfiguration, provider.getId());
if (task != null && task.isEnabled()) {
activeProviders.put(provider, task);
}
}
if (!activeProviders.isEmpty()) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
ConfigurationPerRunnerSettings configurationSettings = state.getConfigurationSettings();
DataContext projectContext = SimpleDataContext.getProjectContext(myProject);
final DataContext dataContext = configurationSettings != null ? SimpleDataContext
.getSimpleContext(BeforeRunTaskProvider.RUNNER_ID, configurationSettings.getRunnerId(), projectContext) : projectContext;
for (BeforeRunTaskProvider<BeforeRunTask> provider : activeProviders.keySet()) {
if(!provider.executeTask(dataContext, runConfiguration, activeProviders.get(provider))) {
return;
}
}
DumbService.getInstance(myProject).smartInvokeLater(startRunnable);
}
});
}
else {
startRunnable.run();
}
}
else {
startRunnable.run();
}
}
@Override
public void startRunProfile(@NotNull final RunProfileStarter starter, @NotNull final RunProfileState state,
@NotNull final Project project, @NotNull final Executor executor, @NotNull final ExecutionEnvironment env) {
final RunContentDescriptor reuseContent = ExecutionManager.getInstance(project).getContentManager().getReuseContent(executor, env.getContentToReuse());
final RunProfile profile = env.getRunProfile();
Runnable startRunnable = new Runnable() {
public void run() {
boolean started = false;
try {
if (project.isDisposed()) return;
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarting(profile);
final RunContentDescriptor descriptor = starter.execute(project, executor, state, reuseContent, env);
if (descriptor != null) {
ExecutionManager.getInstance(project).getContentManager().showRunContent(executor, descriptor);
final ProcessHandler processHandler = descriptor.getProcessHandler();
if (processHandler != null) {
processHandler.startNotify();
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarted(profile, processHandler);
started = true;
processHandler.addProcessListener(new ProcessExecutionListener(project, profile, processHandler));
}
}
if (!activeProviders.isEmpty()) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
ConfigurationPerRunnerSettings configurationSettings = state.getConfigurationSettings();
DataContext projectContext = SimpleDataContext.getProjectContext(myProject);
final DataContext dataContext = configurationSettings != null ? SimpleDataContext
.getSimpleContext(BeforeRunTaskProvider.RUNNER_ID, configurationSettings.getRunnerId(), projectContext) : projectContext;
for (BeforeRunTaskProvider<BeforeRunTask> provider : activeProviders.keySet()) {
if(!provider.executeTask(dataContext, runConfiguration, activeProviders.get(provider))) {
return;
}
}
DumbService.getInstance(myProject).smartInvokeLater(startRunnable);
}
});
}
else {
startRunnable.run();
}
}
else {
startRunnable.run();
catch (ExecutionException e) {
ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), profile, e);
}
if (!started) {
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(profile);
}
}
};
antAwareRunnable.run();
//ApplicationManager.getApplication().invokeLater(antAwareRunnable);
if (ApplicationManager.getApplication().isUnitTestMode()) {
startRunnable.run();
}
else {
compileAndRun(startRunnable, profile, state);
}
}
@NotNull
public String getComponentName() {
return "ExecutionManager";
}
private static class ProcessExecutionListener extends ProcessAdapter {
private final Project myProject;
private final RunProfile myProfile;
private final ProcessHandler myProcessHandler;
public ProcessExecutionListener(Project project, RunProfile profile, ProcessHandler processHandler) {
myProject = project;
myProfile = profile;
myProcessHandler = processHandler;
}
@Override
public void processTerminated(ProcessEvent event) {
myProject.getMessageBus().syncPublisher(EXECUTION_TOPIC).processTerminated(myProfile, myProcessHandler);
}
@Override
public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
myProject.getMessageBus().syncPublisher(EXECUTION_TOPIC).processTerminating(myProfile, myProcessHandler);
}
}
}
@@ -92,7 +92,7 @@ public class ActionButton extends JComponent implements ActionButtonComponent {
}
protected boolean isButtonEnabled() {
return myPresentation.isEnabled();
return isEnabled() && myPresentation.isEnabled();
}
private void onMousePresenceChanged(boolean setInfo) {
@@ -4649,7 +4649,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
public synchronized void update(int startLine, int newEndLine, int oldEndLine) {
final int lineWidthSize = myLineWidths.size();
if (lineWidthSize == 0) {
if (lineWidthSize == 0 || myDocument.getTextLength() <= 0) {
reset();
}
else {
@@ -51,6 +51,7 @@ public final class VcsConfiguration implements PersistentStateComponent<Element>
@NonNls private static final String VALUE_ATTR = "value";
@NonNls private static final String CONFIRM_MOVE_TO_FAILED_COMMIT_ELEMENT = "confirmMoveToFailedCommit";
@NonNls private static final String CONFIRM_REMOVE_EMPTY_CHANGELIST_ELEMENT = "confirmRemoveEmptyChangelist";
private Project myProject;
public boolean OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT = true;
@@ -164,10 +165,14 @@ public final class VcsConfiguration implements PersistentStateComponent<Element>
public void readExternal(Element element) throws InvalidDataException {
DefaultJDOMExternalizer.readExternal(this, element);
final Element child = element.getChild(CONFIRM_MOVE_TO_FAILED_COMMIT_ELEMENT);
Element child = element.getChild(CONFIRM_MOVE_TO_FAILED_COMMIT_ELEMENT);
if (child != null) {
MOVE_TO_FAILED_COMMIT_CHANGELIST = VcsShowConfirmationOption.Value.fromString(child.getAttributeValue(VALUE_ATTR));
}
child = element.getChild(CONFIRM_REMOVE_EMPTY_CHANGELIST_ELEMENT);
if (child != null) {
REMOVE_EMPTY_INACTIVE_CHANGELISTS = VcsShowConfirmationOption.Value.fromString(child.getAttributeValue(VALUE_ATTR));
}
final List messages = element.getChildren(MESSAGE_ELEMENT_NAME);
for (final Object message : messages) {
saveCommitMessage(((Element)message).getAttributeValue(VALUE_ATTR));
@@ -188,6 +193,11 @@ public final class VcsConfiguration implements PersistentStateComponent<Element>
confirmChild.setAttribute(VALUE_ATTR, MOVE_TO_FAILED_COMMIT_CHANGELIST.toString());
element.addContent(confirmChild);
}
if (REMOVE_EMPTY_INACTIVE_CHANGELISTS != VcsShowConfirmationOption.Value.SHOW_CONFIRMATION) {
Element confirmChild = new Element(CONFIRM_REMOVE_EMPTY_CHANGELIST_ELEMENT);
confirmChild.setAttribute(VALUE_ATTR, REMOVE_EMPTY_INACTIVE_CHANGELISTS.toString());
element.addContent(confirmChild);
}
for (String message : myLastCommitMessages) {
final Element messageElement = new Element(MESSAGE_ELEMENT_NAME);
messageElement.setAttribute(VALUE_ATTR, message);
@@ -115,6 +115,11 @@ public class IdeaSpecificSettings {
replaceModuleRelatedRoots(model.getProject(), modifiableModel, libElement, OrderRootType.CLASSES, RELATIVE_MODULE_CLS);
replaceModuleRelatedRoots(model.getProject(), modifiableModel, libElement, JavadocOrderRootType.getInstance(), RELATIVE_MODULE_JAVADOC);
modifiableModel.commit();
} else {
final Library library = EclipseClasspathReader.findLibraryByName(model.getProject(), libName);
if (library != null) {
appendLibraryScope(model, libElement, library);
}
}
}
overrideModulesScopes(root, model);
+1
View File
@@ -252,6 +252,7 @@
<packaging.artifactType implementation="com.intellij.packaging.impl.artifacts.JarArtifactType" order="first"/>
<packaging.artifactType implementation="com.intellij.packaging.impl.artifacts.PlainArtifactType" order="last"/>
<compiler.additionalCompileScopeProvider implementation="com.intellij.packaging.impl.compiler.ArtifactAdditionalCompileScopeProvider"/>
<compiler implementation="com.intellij.packaging.impl.compiler.ArtifactsCompiler" id="artifactsCompiler"/>
<lookup.charFilter implementation="com.intellij.codeInsight.completion.JavaCharFilter" id="java"/>