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

This commit is contained in:
Kirill Kalishev
2010-07-27 13:21:30 +04:00
216 changed files with 2475 additions and 1708 deletions
+2 -2
View File
@@ -3,15 +3,14 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/plugins/InspectionGadgets/InspectionGadgetsPlugin.iml" filepath="$PROJECT_DIR$/plugins/InspectionGadgets/InspectionGadgetsPlugin.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/IntelliLang/IntelliLang.iml" filepath="$PROJECT_DIR$/plugins/IntelliLang/IntelliLang.iml" group="plugins/IntelliLang" />
<module fileurl="file://$PROJECT_DIR$/plugins/IntelliLang/IntelliLang-java.iml" filepath="$PROJECT_DIR$/plugins/IntelliLang/IntelliLang-java.iml" group="plugins/IntelliLang" />
<module fileurl="file://$PROJECT_DIR$/plugins/IntelliLang/IntelliLang-javaee.iml" filepath="$PROJECT_DIR$/plugins/IntelliLang/IntelliLang-javaee.iml" group="plugins/IntelliLang" />
<module fileurl="file://$PROJECT_DIR$/plugins/IntelliLang/IntelliLang-xml.iml" filepath="$PROJECT_DIR$/plugins/IntelliLang/IntelliLang-xml.iml" group="plugins/IntelliLang" />
<module fileurl="file://$PROJECT_DIR$/plugins/IntelliLang/IntelliLangJava.iml" filepath="$PROJECT_DIR$/plugins/IntelliLang/IntelliLangJava.iml" group="plugins/IntelliLang" />
<module fileurl="file://$PROJECT_DIR$/plugins/IntentionPowerPak/IntentionPowerPackPlugin.iml" filepath="$PROJECT_DIR$/plugins/IntentionPowerPak/IntentionPowerPackPlugin.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/RegExpSupport/RegExpSupport.iml" filepath="$PROJECT_DIR$/RegExpSupport/RegExpSupport.iml" />
<module fileurl="file://$PROJECT_DIR$/platform/annotations/annotations.iml" filepath="$PROJECT_DIR$/platform/annotations/annotations.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/plugins/ant/ant.iml" filepath="$PROJECT_DIR$/plugins/ant/ant.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/relaxng/relaxng.iml" filepath="$PROJECT_DIR$/plugins/relaxng/relaxng.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/platform/boot/boot.iml" filepath="$PROJECT_DIR$/platform/boot/boot.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/bootstrap/bootstrap.iml" filepath="$PROJECT_DIR$/platform/bootstrap/bootstrap.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/build/build.iml" filepath="$PROJECT_DIR$/build/build.iml" />
@@ -68,6 +67,7 @@
<module fileurl="file://$PROJECT_DIR$/platform/platform-resources/platform-resources.iml" filepath="$PROJECT_DIR$/platform/platform-resources/platform-resources.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/platform-resources-en/platform-resources-en.iml" filepath="$PROJECT_DIR$/platform/platform-resources-en/platform-resources-en.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/plugins/properties/properties.iml" filepath="$PROJECT_DIR$/plugins/properties/properties.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/relaxng/relaxng.iml" filepath="$PROJECT_DIR$/plugins/relaxng/relaxng.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/resources/resources.iml" filepath="$PROJECT_DIR$/resources/resources.iml" />
<module fileurl="file://$PROJECT_DIR$/resources-en/resources-en.iml" filepath="$PROJECT_DIR$/resources-en/resources-en.iml" />
<module fileurl="file://$PROJECT_DIR$/platform/smRunner/smRunner.iml" filepath="$PROJECT_DIR$/platform/smRunner/smRunner.iml" group="platform" />
+1 -1
View File
@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA" type="Application" factoryName="Application">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<extension name="coverage" enabled="false" sample_coverage="true" runner="idea" merge="false" />
<extension name="snapshooter" />
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
<option name="VM_PARAMETERS" value=" -ea -Xbootclasspath/p:../out/classes/production/boot -Xmx192m -Didea.is.internal=true -XX:MaxPermSize=150m " />
+2 -2
View File
@@ -67,8 +67,8 @@ def wire_build_date(String buildNumber) {
target('default': 'The default target') {
depends(compile)
layoutAll(
buildNumber: "IC-90.SNAPSHOT",
version: "Maia",
buildNumber: "IC-X.SNAPSHOT",
version: "IdeaX",
system_selector: "IntelliJIdeaCE10",
jdk_req: "1.6*",
vmoptions: "-Xms128m -Xmx512m -XX:MaxPermSize=250m -ea",
@@ -13,14 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.impl.javaCompiler;
package com.intellij.compiler;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.extensions.ExtensionPointName;
/**
* @author Eugene Zhuravlev
* Date: Aug 19, 2008
*/
public interface DependencyProcessor {
ExtensionPointName<DependencyProcessor> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.compiler.makeDependencyProcessor");
void processDependencies(CompileContext context, int classQualifiedName);
}
@@ -77,15 +77,13 @@ import com.intellij.psi.PsiCompiledElement;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Chunk;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.*;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.OrderedSet;
import gnu.trove.TIntHashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -957,70 +955,149 @@ public class CompileDriver {
final Set<FileType> generatedTypes = new HashSet<FileType>();
Collection<VirtualFile> chunkFiles = chunkMap.get(currentChunk);
try {
for (int currentCompiler = 0, translatorsLength = translators.length; currentCompiler < translatorsLength; currentCompiler++) {
sink.setCurrentCompilerIndex(currentCompiler);
final TranslatingCompiler compiler = translators[currentCompiler];
if (context.getProgressIndicator().isCanceled()) {
throw new ExitException(ExitStatus.CANCELLED);
int round = 0;
final Set<VirtualFile> filesToRecompile = new HashSet<VirtualFile>();
final Set<VirtualFile> allDependent = new HashSet<VirtualFile>();
Collection<VirtualFile> dependentFiles = Collections.emptyList();
final Function<Pair<int[], Set<VirtualFile>>, Pair<int[], Set<VirtualFile>>> dependencyFilter = new DependentClassesCumulativeFilter();
do {
for (int currentCompiler = 0, translatorsLength = translators.length; currentCompiler < translatorsLength; currentCompiler++) {
sink.setCurrentCompilerIndex(currentCompiler);
final TranslatingCompiler compiler = translators[currentCompiler];
if (context.getProgressIndicator().isCanceled()) {
throw new ExitException(ExitStatus.CANCELLED);
}
DumbService.getInstance(myProject).waitForSmartMode();
if (round == 0) {
if (snapshot == null || ContainerUtil.intersects(generatedTypes, compilerManager.getRegisteredInputTypes(compiler))) {
// rescan snapshot if previously generated files may influence the input of this compiler
snapshot = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile[]>() {
public VirtualFile[] compute() {
return context.getCompileScope().getFiles(null, true);
}
});
recalculateChunkToFilesMap(context, sortedChunks, snapshot, chunkMap);
chunkFiles = chunkMap.get(currentChunk);
total = snapshot.length * translatorsLength;
}
}
final CompileContextEx _context;
if (compiler instanceof IntermediateOutputCompiler) {
// wrap compile context so that output goes into intermediate directories
final IntermediateOutputCompiler _compiler = (IntermediateOutputCompiler)compiler;
_context = new CompileContextExProxy(context) {
public VirtualFile getModuleOutputDirectory(final Module module) {
return getGenerationOutputDir(_compiler, module, false);
}
public VirtualFile getModuleOutputDirectoryForTests(final Module module) {
return getGenerationOutputDir(_compiler, module, true);
}
};
}
else {
_context = context;
}
final boolean compiledSomething =
compileSources(_context, currentChunk, compiler, chunkFiles, round == 0? forceCompile : true, isRebuild, trackDependencies, onlyCheckStatus, sink);
processed += chunkFiles.size();
_context.getProgressIndicator().setFraction(((double)processed) / total);
if (compiledSomething) {
generatedTypes.addAll(compilerManager.getRegisteredOutputTypes(compiler));
}
if (_context.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
throw new ExitException(ExitStatus.ERRORS);
}
didSomething |= compiledSomething;
}
DumbService.getInstance(myProject).waitForSmartMode();
final boolean hasUnprocessedTraverseRoots = context.getDependencyCache().hasUnprocessedTraverseRoots();
if (!isRebuild && (didSomething || hasUnprocessedTraverseRoots)) {
final Set<VirtualFile> compiledWithSuccess;
final Set<VirtualFile> compiledWithErrors = CacheUtils.getFilesCompiledWithErrors(context);
if (compiledWithErrors.isEmpty()) {
compiledWithSuccess = sink.getCompiledSources();
}
else {
compiledWithSuccess = new HashSet<VirtualFile>();
compiledWithSuccess.addAll(sink.getCompiledSources());
compiledWithSuccess.removeAll(compiledWithErrors);
}
filesToRecompile.removeAll(compiledWithSuccess);
filesToRecompile.addAll(compiledWithErrors);
if (snapshot == null || ContainerUtil.intersects(generatedTypes, compilerManager.getRegisteredInputTypes(compiler))) {
// rescan snapshot if previously generated files may influence the input of this compiler
snapshot = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile[]>() {
public VirtualFile[] compute() {
return context.getCompileScope().getFiles(null, true);
}
});
final Map<Module, List<VirtualFile>> moduleToFilesMap = CompilerUtil.buildModuleToFilesMap(context, snapshot);
for (Chunk<Module> moduleChunk : sortedChunks) {
List<VirtualFile> files = Collections.emptyList();
for (Module module : moduleChunk.getNodes()) {
final List<VirtualFile> moduleFiles = moduleToFilesMap.get(module);
if (moduleFiles != null) {
files = ContainerUtil.concat(files, moduleFiles);
dependentFiles = CacheUtils.findDependentFiles(context, compiledWithSuccess, dependencyFilter);
if (ourDebugMode) {
if (!dependentFiles.isEmpty()) {
for (VirtualFile dependentFile : dependentFiles) {
System.out.println("FOUND TO RECOMPILE: " + dependentFile.getPresentableUrl());
}
}
chunkMap.put(moduleChunk, files);
else {
System.out.println("NO FILES TO RECOMPILE");
}
}
total = snapshot.length * translatorsLength;
chunkFiles = chunkMap.get(currentChunk);
}
final CompileContextEx _context;
if (compiler instanceof IntermediateOutputCompiler) {
// wrap compile context so that output goes into intermediate directories
final IntermediateOutputCompiler _compiler = (IntermediateOutputCompiler)compiler;
_context = new CompileContextExProxy(context) {
public VirtualFile getModuleOutputDirectory(final Module module) {
return getGenerationOutputDir(_compiler, module, false);
if (!dependentFiles.isEmpty()) {
filesToRecompile.addAll(dependentFiles);
allDependent.addAll(dependentFiles);
if (context.getProgressIndicator().isCanceled() || context.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
break;
}
public VirtualFile getModuleOutputDirectoryForTests(final Module module) {
return getGenerationOutputDir(_compiler, module, true);
final List<VirtualFile> filesInScope = getFilesInScope(context, currentChunk, dependentFiles);
if (filesInScope.isEmpty()) {
break;
}
};
}
else {
_context = context;
}
final boolean compiledSomething =
compileSources(_context, currentChunk, compiler, chunkFiles, forceCompile, isRebuild, trackDependencies, onlyCheckStatus, sink);
processed += chunkFiles.size();
_context.getProgressIndicator().setFraction(((double)processed) / total);
if (compiledSomething) {
generatedTypes.addAll(compilerManager.getRegisteredOutputTypes(compiler));
context.getDependencyCache().clearTraverseRoots();
chunkFiles = filesInScope;
total += chunkFiles.size() * translators.length;
}
didSomething |= (hasUnprocessedTraverseRoots != context.getDependencyCache().hasUnprocessedTraverseRoots());
}
if (_context.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
throw new ExitException(ExitStatus.ERRORS);
}
didSomething |= compiledSomething;
round++;
}
while (!dependentFiles.isEmpty() && context.getMessageCount(CompilerMessageCategory.ERROR) == 0);
if (CompilerConfiguration.MAKE_ENABLED) {
if (!context.getProgressIndicator().isCanceled()) {
// when cancelled pretend nothing was compiled and next compile will compile everything from the scratch
final ProgressIndicator indicator = context.getProgressIndicator();
final DependencyCache cache = context.getDependencyCache();
indicator.pushState();
indicator.setText(CompilerBundle.message("progress.updating.caches"));
indicator.setText2("");
cache.update();
indicator.setText(CompilerBundle.message("progress.saving.caches"));
cache.resetState();
indicator.popState();
}
}
if (context.getMessageCount(CompilerMessageCategory.ERROR) != 0) {
filesToRecompile.addAll(allDependent);
}
if (filesToRecompile.size() > 0) {
sink.add(null, Collections.<TranslatingCompiler.OutputItem>emptyList(), VfsUtil.toVirtualFileArray(filesToRecompile));
}
}
catch (CacheCorruptedException e) {
LOG.info(e);
context.requestRebuildNextTime(e.getMessage());
}
finally {
if (context.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
@@ -1034,7 +1111,7 @@ public class CompileDriver {
ProgressManager.getInstance().executeNonCancelableSection(new Runnable() {
public void run() {
try {
final Collection<VirtualFile> deps = CacheUtils.findDependentFiles(context, Collections.<VirtualFile>emptySet(), null, null);
final Collection<VirtualFile> deps = CacheUtils.findDependentFiles(context, Collections.<VirtualFile>emptySet(), null);
if (deps.size() > 0) {
TranslatingCompilerFilesMonitor.getInstance().update(context, null, Collections.<TranslatingCompiler.OutputItem>emptyList(),
VfsUtil.toVirtualFileArray(deps));
@@ -1059,6 +1136,37 @@ public class CompileDriver {
return didSomething;
}
private static List<VirtualFile> getFilesInScope(final CompileContextEx context, final Chunk<Module> chunk, final Collection<VirtualFile> files) {
final List<VirtualFile> filesInScope = new ArrayList<VirtualFile>(files.size());
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
for (VirtualFile file : files) {
if (context.getCompileScope().belongs(file.getUrl())) {
final Module module = context.getModuleByFile(file);
if (chunk.getNodes().contains(module)) {
filesInScope.add(file);
}
}
}
}
});
return filesInScope;
}
private static void recalculateChunkToFilesMap(CompileContextEx context, List<Chunk<Module>> allChunks, VirtualFile[] snapshot, Map<Chunk<Module>, Collection<VirtualFile>> chunkMap) {
final Map<Module, List<VirtualFile>> moduleToFilesMap = CompilerUtil.buildModuleToFilesMap(context, snapshot);
for (Chunk<Module> moduleChunk : allChunks) {
List<VirtualFile> files = Collections.emptyList();
for (Module module : moduleChunk.getNodes()) {
final List<VirtualFile> moduleFiles = moduleToFilesMap.get(module);
if (moduleFiles != null) {
files = ContainerUtil.concat(files, moduleFiles);
}
}
chunkMap.put(moduleChunk, files);
}
}
private interface FileProcessingCompilerAdapterFactory {
FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler);
}
@@ -1167,11 +1275,14 @@ public class CompileDriver {
final ArrayList<Trinity<File, String, Boolean>> toDelete = new ArrayList<Trinity<File, String, Boolean>>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
TranslatingCompilerFilesMonitor.getInstance()
.collectFiles(context, (TranslatingCompiler)compiler, Arrays.<VirtualFile>asList(allSources).iterator(), true
/*pass true to make sure that every source in scope file is processed*/, false
/*important! should pass false to enable collection of files to delete*/,
new ArrayList<VirtualFile>(), toDelete);
TranslatingCompilerFilesMonitor.getInstance().collectFiles(
context,
(TranslatingCompiler)compiler, Arrays.<VirtualFile>asList(allSources).iterator(),
true /*pass true to make sure that every source in scope file is processed*/,
false /*important! should pass false to enable collection of files to delete*/,
new ArrayList<VirtualFile>(),
toDelete
);
}
});
for (Trinity<File, String, Boolean> trinity : toDelete) {
@@ -1532,7 +1643,6 @@ public class CompileDriver {
context.getProgressIndicator().pushState();
final boolean[] wereFilesDeleted = new boolean[]{false};
boolean traverseRootsProcessed = false;
try {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
@@ -1589,16 +1699,14 @@ public class CompileDriver {
}
}
final boolean hadUnprocessedTraverseRoots = context.getDependencyCache().hasUnprocessedTraverseRoots();
if ((wereFilesDeleted[0] || hadUnprocessedTraverseRoots || !toCompile.isEmpty()) && context.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
if ((wereFilesDeleted[0] || !toCompile.isEmpty()) && context.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
compiler.compile(context, moduleChunk, VfsUtil.toVirtualFileArray(toCompile), sink);
traverseRootsProcessed = hadUnprocessedTraverseRoots != context.getDependencyCache().hasUnprocessedTraverseRoots();
}
}
finally {
context.getProgressIndicator().popState();
}
return !toCompile.isEmpty() || traverseRootsProcessed || wereFilesDeleted[0];
return !toCompile.isEmpty() || wereFilesDeleted[0];
}
private static boolean syncOutputDir(final CompileContextEx context, final Collection<Trinity<File, String, Boolean>> toDelete) throws CacheCorruptedException {
@@ -2277,6 +2385,7 @@ public class CompileDriver {
private final CompileContextEx myContext;
private final TranslatingCompiler[] myCompilers;
private int myCurrentCompilerIdx;
private final Set<VirtualFile> myCompiledSources = new HashSet<VirtualFile>();
//private LinkedBlockingQueue<Future> myFutures = new LinkedBlockingQueue<Future>();
private TranslatorsOutputSink(CompileContextEx context, TranslatingCompiler[] compilers) {
@@ -2288,7 +2397,17 @@ public class CompileDriver {
myCurrentCompilerIdx = index;
}
public Set<VirtualFile> getCompiledSources() {
return Collections.unmodifiableSet(myCompiledSources);
}
public void add(final String outputRoot, final Collection<TranslatingCompiler.OutputItem> items, final VirtualFile[] filesToRecompile) {
for (TranslatingCompiler.OutputItem item : items) {
final VirtualFile file = item.getSourceFile();
if (file != null) {
myCompiledSources.add(file);
}
}
final TranslatingCompiler compiler = myCompilers[myCurrentCompilerIdx];
if (compiler instanceof IntermediateOutputCompiler) {
final LocalFileSystem lfs = LocalFileSystem.getInstance();
@@ -2368,7 +2487,7 @@ public class CompileDriver {
}
}
private void addItemToMap(Map<String, Collection<TranslatingCompiler.OutputItem>> map, String outputDir, TranslatingCompiler.OutputItem item) {
private static void addItemToMap(Map<String, Collection<TranslatingCompiler.OutputItem>> map, String outputDir, TranslatingCompiler.OutputItem item) {
Collection<TranslatingCompiler.OutputItem> collection = map.get(outputDir);
if (collection == null) {
collection = new ArrayList<TranslatingCompiler.OutputItem>();
@@ -2392,4 +2511,21 @@ public class CompileDriver {
}
}
}
private static class DependentClassesCumulativeFilter implements Function<Pair<int[], Set<VirtualFile>>, Pair<int[], Set<VirtualFile>>> {
private final TIntHashSet myProcessedNames = new TIntHashSet();
private final Set<VirtualFile> myProcessedFiles = new HashSet<VirtualFile>();
public Pair<int[], Set<VirtualFile>> fun(Pair<int[], Set<VirtualFile>> deps) {
final TIntHashSet currentDeps = new TIntHashSet(deps.getFirst());
currentDeps.removeAll(myProcessedNames.toArray());
myProcessedNames.addAll(deps.getFirst());
final Set<VirtualFile> depFiles = new HashSet<VirtualFile>(deps.getSecond());
depFiles.removeAll(myProcessedFiles);
myProcessedFiles.addAll(deps.getSecond());
return new Pair<int[], Set<VirtualFile>>(currentDeps.toArray(), depFiles);
}
}
}
@@ -1212,9 +1212,22 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
if (srcFile != null) {
final SourceFileInfo srcInfo = loadSourceInfo(srcFile);
if (srcInfo != null) {
final boolean srcWillBeDeleted = VfsUtil.isAncestor(eventFile, srcFile, false);
for (int projectId : srcInfo.getProjectIds().toArray()) {
if (srcInfo.isAssociated(projectId, filePath)) {
addSourceForRecompilation(projectId, srcFile, srcInfo);
if (srcWillBeDeleted) {
if (LOG.isDebugEnabled() || ourDebugMode) {
final String message = "Unschedule recompilation because of deletion " + srcFile.getPresentableUrl();
LOG.debug(message);
if (ourDebugMode) {
System.out.println(message);
}
}
removeSourceForRecompilation(projectId, Math.abs(getFileId(srcFile)));
}
else {
addSourceForRecompilation(projectId, srcFile, srcInfo);
}
}
}
}
@@ -1226,6 +1239,8 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
final TIntHashSet projects = srcInfo.getProjectIds();
if (!projects.isEmpty()) {
final ScheduleOutputsForDeletionProc deletionProc = new ScheduleOutputsForDeletionProc(file.getUrl());
deletionProc.setRootBeingDeleted(eventFile);
final int sourceFileId = Math.abs(getFileId(file));
for (int projectId : projects.toArray()) {
// mark associated outputs for deletion
srcInfo.processOutputPaths(projectId, deletionProc);
@@ -1236,7 +1251,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
System.out.println(message);
}
}
removeSourceForRecompilation(projectId, Math.abs(getFileId(file)));
removeSourceForRecompilation(projectId, sourceFileId);
}
}
}
@@ -1381,18 +1396,29 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
private class ScheduleOutputsForDeletionProc implements Proc {
private final String mySrcUrl;
private final LocalFileSystem myFileSystem;
@Nullable
private VirtualFile myRootBeingDeleted;
private ScheduleOutputsForDeletionProc(final String srcUrl) {
mySrcUrl = srcUrl;
myFileSystem = LocalFileSystem.getInstance();
}
public void setRootBeingDeleted(@Nullable VirtualFile rootBeingDeleted) {
myRootBeingDeleted = rootBeingDeleted;
}
public boolean execute(final int projectId, String outputPath) {
final VirtualFile outFile = myFileSystem.findFileByPath(outputPath);
if (outFile != null) { // not deleted yet
final OutputFileInfo outputInfo = loadOutputInfo(outFile);
final String classname = outputInfo != null? outputInfo.getClassName() : null;
markOutputPathForDeletion(projectId, outputPath, classname, mySrcUrl);
if (myRootBeingDeleted != null && VfsUtil.isAncestor(myRootBeingDeleted, outFile, false)) {
unmarkOutputPathForDeletion(outputPath);
}
else {
final OutputFileInfo outputInfo = loadOutputInfo(outFile);
final String classname = outputInfo != null? outputInfo.getClassName() : null;
markOutputPathForDeletion(projectId, outputPath, classname, mySrcUrl);
}
}
return true;
}
@@ -47,6 +47,4 @@ public interface BackendCompiler {
void compileFinished();
@Nullable
DependencyProcessor getDependencyProcessor();
}
@@ -26,7 +26,10 @@ import com.intellij.compiler.*;
import com.intellij.compiler.classParsing.AnnotationConstantValue;
import com.intellij.compiler.classParsing.MethodInfo;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.make.*;
import com.intellij.compiler.make.Cache;
import com.intellij.compiler.make.CacheCorruptedException;
import com.intellij.compiler.make.DependencyCache;
import com.intellij.compiler.make.MakeUtil;
import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
import com.intellij.ide.util.projectWizard.JavaModuleBuilder;
import com.intellij.openapi.application.Application;
@@ -38,7 +41,6 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.JavaModuleType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.Sdk;
@@ -52,10 +54,8 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Chunk;
import com.intellij.util.Function;
import com.intellij.util.cls.ClsFormatException;
import gnu.trove.THashMap;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -74,20 +74,18 @@ public class BackendCompilerWrapper {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.javaCompiler.BackendCompilerWrapper");
private final BackendCompiler myCompiler;
private final Set<VirtualFile> mySuccesfullyCompiledJavaFiles; // VirtualFile
private final CompileContextEx myCompileContext;
private final List<VirtualFile> myFilesToCompile;
private final TranslatingCompiler.OutputSink mySink;
private final Chunk<Module> myChunk;
private final Project myProject;
private final Set<VirtualFile> myFilesToRecompile;
private final Map<Module, VirtualFile> myModuleToTempDirMap = new THashMap<Module, VirtualFile>();
private final ProjectFileIndex myProjectFileIndex;
@NonNls private static final String PACKAGE_ANNOTATION_FILE_NAME = "package-info.java";
private static final FileObject myStopThreadToken = new FileObject(new File(""), new byte[0]);
public final Map<String, Set<CompiledClass>> myFileNameToSourceMap= new THashMap<String, Set<CompiledClass>>();
private final Set<VirtualFile> myProcessedPackageInfos = new HashSet<VirtualFile>();
public BackendCompilerWrapper(Chunk<Module> chunk, @NotNull final Project project,
@NotNull List<VirtualFile> filesToCompile,
@@ -98,44 +96,19 @@ public class BackendCompilerWrapper {
myCompiler = compiler;
myCompileContext = compileContext;
myFilesToCompile = filesToCompile;
myFilesToRecompile = new HashSet<VirtualFile>(filesToCompile);
mySink = sink;
myProjectFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
mySuccesfullyCompiledJavaFiles = new HashSet<VirtualFile>(filesToCompile.size());
}
public void compile() throws CompilerException, CacheCorruptedException {
Application application = ApplicationManager.getApplication();
final Set<VirtualFile> allDependent = new HashSet<VirtualFile>();
COMPILE:
try {
if (!myFilesToCompile.isEmpty()) {
if (application.isUnitTestMode()) {
saveTestData();
}
compileModules(buildModuleToFilesMap(myFilesToCompile));
}
Collection<VirtualFile> dependentFiles;
do {
dependentFiles = CacheUtils.findDependentFiles(myCompileContext, mySuccesfullyCompiledJavaFiles, myCompiler.getDependencyProcessor(), DEPENDENCY_FILTER);
if (!dependentFiles.isEmpty()) {
myFilesToRecompile.addAll(dependentFiles);
allDependent.addAll(dependentFiles);
if (myCompileContext.getProgressIndicator().isCanceled() || myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
break COMPILE;
}
final List<VirtualFile> filesInScope = getFilesInScope(dependentFiles);
if (filesInScope.isEmpty()) {
break;
}
myCompileContext.getDependencyCache().clearTraverseRoots();
compileModules(buildModuleToFilesMap(filesInScope));
}
}
while (!dependentFiles.isEmpty() && myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) == 0);
}
catch (SecurityException e) {
throw new CompilerException(CompilerBundle.message("error.compiler.process.not.started", e.getMessage()), e);
@@ -153,34 +126,22 @@ public class BackendCompilerWrapper {
myModuleToTempDirMap.clear();
}
// do not update caches if cancelled because there is a chance that they will be incomplete
if (CompilerConfiguration.MAKE_ENABLED) {
if (!myCompileContext.getProgressIndicator().isCanceled()) {
// when cancelled pretend nothing was compiled and next compile will compile everything from the scratch
final ProgressIndicator indicator = myCompileContext.getProgressIndicator();
final DependencyCache cache = myCompileContext.getDependencyCache();
indicator.pushState();
indicator.setText(CompilerBundle.message("progress.updating.caches"));
indicator.setText2("");
cache.update();
indicator.setText(CompilerBundle.message("progress.saving.caches"));
cache.resetState();
indicator.popState();
if (!myFilesToCompile.isEmpty() && myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
// package-info.java hack
final List<TranslatingCompiler.OutputItem> outputs = new ArrayList<TranslatingCompiler.OutputItem>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
for (final VirtualFile file : myFilesToCompile) {
if (PACKAGE_ANNOTATION_FILE_NAME.equals(file.getName()) && !myProcessedPackageInfos.contains(file)) {
outputs.add(new OutputItemImpl(file));
}
}
}
});
if (!outputs.isEmpty()) {
mySink.add(null, outputs, VirtualFile.EMPTY_ARRAY);
}
}
myFilesToRecompile.removeAll(mySuccesfullyCompiledJavaFiles);
if (myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) != 0) {
myFilesToRecompile.addAll(allDependent);
}
final List<TranslatingCompiler.OutputItem> outputs = processPackageInfoFiles();
if (myFilesToRecompile.size() > 0 || outputs.size() > 0) {
mySink.add(null, outputs, VfsUtil.toVirtualFileArray(myFilesToRecompile));
}
}
private Map<Module, List<VirtualFile>> buildModuleToFilesMap(final List<VirtualFile> filesToCompile) {
@@ -190,51 +151,6 @@ public class BackendCompilerWrapper {
return CompilerUtil.buildModuleToFilesMap(myCompileContext, filesToCompile);
}
// package-info.java hack
private List<TranslatingCompiler.OutputItem> processPackageInfoFiles() {
if (myFilesToRecompile.isEmpty()) {
return Collections.emptyList();
}
final List<TranslatingCompiler.OutputItem> outputs = new ArrayList<TranslatingCompiler.OutputItem>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final List<VirtualFile> packageInfoFiles = new ArrayList<VirtualFile>(myFilesToRecompile.size());
for (final VirtualFile file : myFilesToRecompile) {
if (PACKAGE_ANNOTATION_FILE_NAME.equals(file.getName())) {
packageInfoFiles.add(file);
}
}
if (!packageInfoFiles.isEmpty()) {
final Set<VirtualFile> badFiles = getFilesCompiledWithErrors();
for (final VirtualFile packageInfoFile : packageInfoFiles) {
if (!badFiles.contains(packageInfoFile)) {
outputs.add(new OutputItemImpl(packageInfoFile));
myFilesToRecompile.remove(packageInfoFile);
}
}
}
}
});
return outputs;
}
private List<VirtualFile> getFilesInScope(final Collection<VirtualFile> files) {
final List<VirtualFile> filesInScope = new ArrayList<VirtualFile>(files.size());
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
for (VirtualFile file : files) {
if (myCompileContext.getCompileScope().belongs(file.getUrl())) {
final Module module = myCompileContext.getModuleByFile(file);
if (myChunk.getNodes().contains(module)) {
filesInScope.add(file);
}
}
}
}
});
return filesInScope;
}
private void compileModules(final Map<Module, List<VirtualFile>> moduleToFilesMap) throws CompilerException {
myProcessedFilesCount = 0;
try {
@@ -347,21 +263,6 @@ public class BackendCompilerWrapper {
});
}
private final TIntHashSet myProcessedNames = new TIntHashSet();
private final Set<VirtualFile> myProcessedFiles = new HashSet<VirtualFile>();
private final Function<Pair<int[], Set<VirtualFile>>, Pair<int[], Set<VirtualFile>>> DEPENDENCY_FILTER = new Function<Pair<int[], Set<VirtualFile>>, Pair<int[], Set<VirtualFile>>>() {
public Pair<int[], Set<VirtualFile>> fun(Pair<int[], Set<VirtualFile>> deps) {
final TIntHashSet currentDeps = new TIntHashSet(deps.getFirst());
currentDeps.removeAll(myProcessedNames.toArray());
myProcessedNames.addAll(deps.getFirst());
final Set<VirtualFile> depFiles = new HashSet<VirtualFile>(deps.getSecond());
depFiles.removeAll(myProcessedFiles);
myProcessedFiles.addAll(deps.getSecond());
return new Pair<int[], Set<VirtualFile>>(currentDeps.toArray(), depFiles);
}
};
private final Object lock = new Object();
private class SynchedCompilerParsing extends CompilerParsingThread {
@@ -599,8 +500,7 @@ public class BackendCompilerWrapper {
}
private void compileFinished(int exitValue, final ModuleChunk chunk, final String outputDir) {
if (exitValue != 0 && !myCompileContext.getProgressIndicator().isCanceled() &&
myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
if (exitValue != 0 && !myCompileContext.getProgressIndicator().isCanceled() && myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
myCompileContext.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("error.compiler.internal.error", exitValue), null, -1, -1);
}
@@ -610,7 +510,6 @@ public class BackendCompilerWrapper {
try {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Set<VirtualFile> compiledWithErrors = getFilesCompiledWithErrors();
final FileTypeManager typeManager = FileTypeManager.getInstance();
final String outputDirPath = outputDir.replace(File.separatorChar, '/');
try {
@@ -620,7 +519,7 @@ public class BackendCompilerWrapper {
if (LOG.isDebugEnabled()) {
LOG.debug("Building output items for " + root.getPresentableUrl() + "; output dir = " + outputDirPath + "; packagePrefix = \"" + packagePrefix + "\"");
}
buildOutputItemsList(outputDirPath, module, root, typeManager, compiledWithErrors, root, packagePrefix, toRefresh, results);
buildOutputItemsList(outputDirPath, module, root, typeManager, root, packagePrefix, toRefresh, results);
}
}
}
@@ -644,24 +543,8 @@ public class BackendCompilerWrapper {
myFileNameToSourceMap.clear(); // clear the map before the next use
}
private Set<VirtualFile> getFilesCompiledWithErrors() {
CompilerMessage[] messages = myCompileContext.getMessages(CompilerMessageCategory.ERROR);
Set<VirtualFile> compiledWithErrors = Collections.emptySet();
if (messages.length > 0) {
compiledWithErrors = new HashSet<VirtualFile>(messages.length);
for (CompilerMessage message : messages) {
final VirtualFile file = message.getVirtualFile();
if (file != null) {
compiledWithErrors.add(file);
}
}
}
return compiledWithErrors;
}
private void buildOutputItemsList(final String outputDir, Module module, VirtualFile from,
final FileTypeManager typeManager,
final Set<VirtualFile> compiledWithErrors,
final VirtualFile sourceRoot,
final String packagePrefix, final List<File> filesToRefresh, final Map<String, Collection<TranslatingCompiler.OutputItem>> results) throws CacheCorruptedException {
final Ref<CacheCorruptedException> exRef = new Ref<CacheCorruptedException>(null);
@@ -671,7 +554,7 @@ public class BackendCompilerWrapper {
try {
assert child.isValid();
if (!child.isDirectory() && myCompiler.getCompilableFileTypes().contains(typeManager.getFileTypeByFile(child))) {
updateOutputItemsList(outputDir, child, compiledWithErrors, sourceRoot, packagePrefix, filesToRefresh, results);
updateOutputItemsList(outputDir, child, sourceRoot, packagePrefix, filesToRefresh, results);
}
return true;
}
@@ -720,7 +603,7 @@ public class BackendCompilerWrapper {
paths.add(new CompiledClass(classQName, relativePathToSource, pathToClass));
}
private void updateOutputItemsList(final String outputDir, VirtualFile srcFile, Set<VirtualFile> compiledWithErrors,
private void updateOutputItemsList(final String outputDir, VirtualFile srcFile,
VirtualFile sourceRoot,
final String packagePrefix, final List<File> filesToRefresh,
Map<String, Collection<TranslatingCompiler.OutputItem>> results) throws CacheCorruptedException {
@@ -745,6 +628,9 @@ public class BackendCompilerWrapper {
results.put(realLocation.getFirst(), outputs);
}
outputs.add(new OutputItemImpl(realLocation.getSecond(), srcFile));
if (PACKAGE_ANNOTATION_FILE_NAME.equals(srcFile.getName())) {
myProcessedPackageInfos.add(srcFile);
}
if (CompilerConfiguration.MAKE_ENABLED) {
newCache.setPath(cc.qName, realLocation.getSecond());
}
@@ -752,9 +638,6 @@ public class BackendCompilerWrapper {
LOG.debug("Added output item: [outputDir; outputPath; sourceFile] = [" + realLocation.getFirst() + "; " +
realLocation.getSecond() + "; " + srcFile.getPresentableUrl() + "]");
}
if (!compiledWithErrors.contains(srcFile)) {
mySuccesfullyCompiledJavaFiles.add(srcFile);
}
}
else {
myCompileContext.addMessage(CompilerMessageCategory.ERROR, "Failed to copy from temporary location to output directory: " + outputPath + " (see idea.log for details)", null, -1, -1);
@@ -773,7 +656,7 @@ public class BackendCompilerWrapper {
* @param packagePrefix
* @return A 'package'-path to a given src file relative to a specified root. "/" slashes must be used
*/
protected String calcPackagePath(VirtualFile srcFile, VirtualFile sourceRoot, String packagePrefix) {
protected static String calcPackagePath(VirtualFile srcFile, VirtualFile sourceRoot, String packagePrefix) {
final String prefix = packagePrefix != null && packagePrefix.length() > 0 ? packagePrefix.replace('.', '/') + "/" : "";
return prefix + VfsUtil.getRelativePath(srcFile, sourceRoot, '/');
}
@@ -41,10 +41,6 @@ public abstract class ExternalCompiler implements BackendCompiler {
return COMPILABLE_TYPES;
}
public DependencyProcessor getDependencyProcessor() {
return null;
}
@NotNull
public Process launchProcess(@NotNull final ModuleChunk chunk, @NotNull final String outputDir, @NotNull final CompileContext compileContext) throws IOException {
final String[] commands = createStartupCommand(chunk, compileContext, outputDir);
@@ -17,7 +17,6 @@ package com.intellij.compiler.impl.javaCompiler.api;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.impl.javaCompiler.BackendCompiler;
import com.intellij.compiler.impl.javaCompiler.DependencyProcessor;
import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
import com.intellij.compiler.impl.javaCompiler.javac.JavacCompiler;
import com.intellij.compiler.impl.javaCompiler.javac.JavacConfigurable;
@@ -56,10 +55,6 @@ public class CompilerAPICompiler implements BackendCompiler {
myProject = project;
}
public DependencyProcessor getDependencyProcessor() {
return null;
}
public boolean checkCompiler(final CompileScope scope) {
return true;
}
@@ -17,7 +17,6 @@ package com.intellij.compiler.impl.javaCompiler.eclipse;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.impl.javaCompiler.BackendCompiler;
import com.intellij.compiler.impl.javaCompiler.DependencyProcessor;
import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
import com.intellij.compiler.impl.javaCompiler.javac.JavacSettings;
import com.intellij.openapi.application.ApplicationManager;
@@ -58,10 +57,6 @@ public class EclipseEmbeddedCompiler implements BackendCompiler {
myEclipseCompilerDriver = new EclipseCompilerDriver();
}
public DependencyProcessor getDependencyProcessor() {
return null;
}
public boolean checkCompiler(final CompileScope scope) {
return myEclipseCompilerDriver != null && myEclipseExternalCompiler.checkCompiler(scope);
}
@@ -19,9 +19,10 @@ import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerManagerImpl;
import com.intellij.compiler.SymbolTable;
import com.intellij.compiler.classParsing.MethodInfo;
import com.intellij.compiler.impl.javaCompiler.DependencyProcessor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.CompilerMessage;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.compiler.ex.CompileContextEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
@@ -31,6 +32,7 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.StringBuilderSpinAllocator;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -126,9 +128,11 @@ public class CacheUtils {
return true;
}
public static Collection<VirtualFile> findDependentFiles(final CompileContextEx context, final Set<VirtualFile> succesfullyCompiledJavaFiles,
final @Nullable DependencyProcessor additionalDependencyProcessor,
final @Nullable Function<Pair<int[], Set<VirtualFile>>, Pair<int[], Set<VirtualFile>>> filter) throws CacheCorruptedException {
public static Collection<VirtualFile> findDependentFiles(
final CompileContextEx context,
final Set<VirtualFile> succesfullyCompiledJavaFiles,
final @Nullable Function<Pair<int[], Set<VirtualFile>>, Pair<int[], Set<VirtualFile>>> filter) throws CacheCorruptedException {
if (!CompilerConfiguration.MAKE_ENABLED) {
return Collections.emptyList();
}
@@ -137,7 +141,7 @@ public class CacheUtils {
final DependencyCache dependencyCache = context.getDependencyCache();
final Pair<int[], Set<VirtualFile>> deps =
dependencyCache.findDependentClasses(context, context.getProject(), succesfullyCompiledJavaFiles, additionalDependencyProcessor);
dependencyCache.findDependentClasses(context, context.getProject(), succesfullyCompiledJavaFiles);
final Pair<int[], Set<VirtualFile>> filteredDeps = filter != null? filter.fun(deps) : deps;
final Set<VirtualFile> dependentFiles = new HashSet<VirtualFile>();
@@ -187,4 +191,20 @@ public class CacheUtils {
return dependentFiles;
}
@NotNull
public static Set<VirtualFile> getFilesCompiledWithErrors(final CompileContextEx context) {
CompilerMessage[] messages = context.getMessages(CompilerMessageCategory.ERROR);
Set<VirtualFile> compiledWithErrors = Collections.emptySet();
if (messages.length > 0) {
compiledWithErrors = new HashSet<VirtualFile>(messages.length);
for (CompilerMessage message : messages) {
final VirtualFile file = message.getVirtualFile();
if (file != null) {
compiledWithErrors.add(file);
}
}
}
return compiledWithErrors;
}
}
@@ -20,9 +20,9 @@
*/
package com.intellij.compiler.make;
import com.intellij.compiler.DependencyProcessor;
import com.intellij.compiler.SymbolTable;
import com.intellij.compiler.classParsing.*;
import com.intellij.compiler.impl.javaCompiler.DependencyProcessor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.diagnostic.Logger;
@@ -37,7 +37,6 @@ import com.intellij.util.cls.ClsUtil;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
@@ -390,15 +389,14 @@ public class DependencyCache {
/**
* @return qualified names of the classes that should be additionally recompiled
*/
public Pair<int[], Set<VirtualFile>> findDependentClasses(CompileContext context, Project project, Set<VirtualFile> successfullyCompiled, @Nullable final DependencyProcessor additionalProcessor)
throws CacheCorruptedException {
public Pair<int[], Set<VirtualFile>> findDependentClasses(CompileContext context, Project project, Set<VirtualFile> successfullyCompiled)
throws CacheCorruptedException {
markDependencies(context, project, successfullyCompiled, additionalProcessor);
markDependencies(context, project, successfullyCompiled);
return new Pair<int[], Set<VirtualFile>>(myMarkedInfos.toArray(), Collections.unmodifiableSet(myMarkedFiles));
}
private void markDependencies(CompileContext context, Project project, final Set<VirtualFile> successfullyCompiled,
@Nullable final DependencyProcessor additionalProcessor) throws CacheCorruptedException {
private void markDependencies(CompileContext context, Project project, final Set<VirtualFile> successfullyCompiled) throws CacheCorruptedException {
try {
if (LOG.isDebugEnabled()) {
LOG.debug("====================Marking dependent files=====================");
@@ -427,7 +425,7 @@ public class DependencyCache {
).run();
}
changedRetentionPolicyDependencyProcessor.checkAnnotationRetentionPolicyChanges(qName);
if (additionalProcessor != null) {
for (DependencyProcessor additionalProcessor : DependencyProcessor.EXTENSION_POINT_NAME.getExtensions()) {
additionalProcessor.processDependencies(context, qName);
}
}
@@ -16,6 +16,7 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.*;
import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Computable;
@@ -187,8 +187,9 @@ public class CreatePropertyFromUsageFix extends CreateFromUsageBaseFix {
LOG.assertTrue(callText != null, myMethodCall.getMethodExpression());
PsiType[] expectedTypes;
PsiType type;
PsiField field = targetClass.findFieldByName(fieldName, true);
if (callText.startsWith(GET_PREFIX)) {
expectedTypes = CreateFromUsageUtils.guessType(myMethodCall, false);
expectedTypes = field != null ? new PsiType[]{field.getType()} : CreateFromUsageUtils.guessType(myMethodCall, false);
type = expectedTypes[0];
}
else if (callText.startsWith(IS_PREFIX)) {
@@ -206,7 +207,7 @@ public class CreatePropertyFromUsageFix extends CreateFromUsageBaseFix {
IdeDocumentHistory.getInstance(project).includeCurrentPlaceAsChangePlace();
try {
PsiField field = targetClass.findFieldByName(fieldName, true);
if (field == null) {
field = factory.createField(fieldName, type);
PsiUtil.setModifierProperty(field, PsiModifier.STATIC, isStatic);
@@ -46,9 +46,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -1290,32 +1288,26 @@ public class JavaDocInfoGenerator {
LinkedList<Pair<PsiDocTag, InheritDocProvider<PsiDocTag>>> collectedTags =
new LinkedList<Pair<PsiDocTag, InheritDocProvider<PsiDocTag>>>();
LinkedList<PsiClassType> holder = new LinkedList<PsiClassType>(Arrays.asList(method.getThrowsList().getReferencedTypes()));
final List<PsiClassType> declaredThrows = new ArrayList<PsiClassType>(Arrays.asList(method.getThrowsList().getReferencedTypes()));
for (int i = localTags.length - 1; i > -1; i--) {
PsiDocTagValue valueElement = localTags[i].getValueElement();
if (valueElement != null) {
boolean contains = false;
for (PsiClassType classType : holder) {
for (Iterator<PsiClassType> iterator = declaredThrows.iterator(); iterator.hasNext();) {
PsiClassType classType = iterator.next();
if (Comparing.strEqual(valueElement.getText(), classType.getClassName())) {
contains = true;
iterator.remove();
break;
}
}
if (contains) continue;
try {
PsiClassType t = (PsiClassType)JavaPsiFacade.getInstance(method.getProject()).getElementFactory()
.createTypeFromText(valueElement.getText(), method);
if (!holder.contains(t)) {
holder.addFirst(t);
}
} catch(IncorrectOperationException e) {} // nonvalid type
collectedTags.addFirst(new Pair<PsiDocTag, InheritDocProvider<PsiDocTag>>(localTags[i], ourEmptyProvider));
}
}
PsiClassType[] trousers = holder.toArray(new PsiClassType[holder.size()]);
PsiClassType[] trousers = declaredThrows.toArray(new PsiClassType[declaredThrows.size()]);
for (PsiClassType trouser : trousers) {
if (trouser != null) {
@@ -254,7 +254,7 @@ public class LocalCanBeFinal extends BaseLocalInspectionTool {
if (!CodeInsightUtilBase.preparePsiElementForWrite(problem.getPsiElement())) return;
PsiElement nameIdentifier = problem.getPsiElement();
if (nameIdentifier == null) return;
PsiVariable psiVariable = (PsiVariable)nameIdentifier.getParent();
PsiVariable psiVariable = PsiTreeUtil.getParentOfType(nameIdentifier, PsiVariable.class, false);
if (psiVariable == null) return;
try {
psiVariable.normalizeDeclaration();
@@ -78,7 +78,7 @@ public class JavaRefactoringSupportProvider extends DefaultRefactoringSupportPro
return new JavaPushDownHandler();
}
public RefactoringActionHandler getExtractModuleHandler() {
public RefactoringActionHandler getExtractInterfaceHandler() {
return new ExtractInterfaceHandler();
}
@@ -175,7 +175,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
}
break;
case SUBTYPE:
if (PsiType.NULL.equals(upperBound)) {
if (PsiType.NULL.equals(upperBound) || TypeConversionUtil.isAssignable(upperBound, type)) {
upperBound = type;
}
}
@@ -819,7 +819,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper()
.isAccessible(method, modifierList, element, accessObjectClass, null)) {
String message =
RefactoringBundle.message("0.with.1.visibility.is.not.accesible.from.2",
RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2",
RefactoringUIUtil.getDescription(method, true),
myChangeInfo.getNewVisibility(),
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
@@ -200,7 +200,7 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor {
}
if (!JavaResolveUtil.isAccessible(myMethod, myTargetClass, copy, call, accessObjectClass, null)) {
final String newVisibility = myNewVisibility == null ? VisibilityUtil.getVisibilityStringToDisplay(myMethod) : myNewVisibility;
String message = RefactoringBundle.message("0.with.1.visibility.is.not.accesible.from.2",
String message = RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2",
RefactoringUIUtil.getDescription(myMethod, true), newVisibility,
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(call), true));
conflicts.putValue(myMethod, message);
@@ -268,7 +268,7 @@ public class IntroduceParameterProcessor extends BaseRefactoringProcessor implem
!JavaPsiFacade.getInstance(myProject).getResolveHelper().isAccessible((PsiMember)element, place, null)) {
String message =
RefactoringBundle.message(
"0.is.not.accesible.from.1.value.for.introduced.parameter.in.that.method.call.will.be.incorrect",
"0.is.not.accessible.from.1.value.for.introduced.parameter.in.that.method.call.will.be.incorrect",
RefactoringUIUtil.getDescription(element, true),
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(place), true));
conflicts.putValue(element, message);
@@ -150,8 +150,10 @@ public class JavaPullUpHandler implements RefactoringActionHandler, PullUpDialog
final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
final PsiDirectory targetDirectory = superClass.getContainingFile().getContainingDirectory();
final PsiPackage targetPackage = targetDirectory != null ? JavaDirectoryService.getInstance().getPackage(targetDirectory) : null;
conflicts
.putAllValues(PullUpConflictsUtil.checkConflicts(infos, mySubclass, superClass, null, null, dialog.getContainmentVerifier()));
.putAllValues(PullUpConflictsUtil.checkConflicts(infos, mySubclass, superClass, targetPackage, targetDirectory, dialog.getContainmentVerifier()));
}
}, "Detecting possible conflicts...", true, myProject)) return false;
if (!conflicts.isEmpty()) {
@@ -28,10 +28,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.util.*;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.RefactoringConflictsUtil;
@@ -43,6 +40,7 @@ import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -56,17 +54,17 @@ public class PullUpConflictsUtil {
public static MultiMap<PsiElement, String> checkConflicts(final MemberInfo[] infos,
PsiClass subclass,
@Nullable PsiClass superClass,
PsiPackage targetPackage,
PsiDirectory targetDirectory,
@NotNull PsiPackage targetPackage,
@NotNull PsiDirectory targetDirectory,
final InterfaceContainmentVerifier interfaceContainmentVerifier) {
return checkConflicts(infos, subclass, superClass, targetPackage, targetDirectory, interfaceContainmentVerifier, true);
}
public static MultiMap<PsiElement, String> checkConflicts(final MemberInfo[] infos,
final PsiClass subclass,
@NotNull final PsiClass subclass,
@Nullable PsiClass superClass,
final PsiPackage targetPackage,
PsiDirectory targetDirectory,
@NotNull final PsiPackage targetPackage,
@NotNull PsiDirectory targetDirectory,
final InterfaceContainmentVerifier interfaceContainmentVerifier,
boolean movedMembers2Super) {
final Set<PsiMember> movedMembers = new HashSet<PsiMember>();
@@ -143,9 +141,20 @@ public class PullUpConflictsUtil {
}
RefactoringConflictsUtil.analyzeModuleConflicts(subclass.getProject(), checkModuleConflictsList,
new UsageInfo[0], targetRepresentativeElement, conflicts);
final String fqName = subclass.getQualifiedName();
final String packageName;
if (fqName != null) {
packageName = StringUtil.getPackageName(fqName);
} else {
final PsiFile psiFile = PsiTreeUtil.getParentOfType(subclass, PsiFile.class);
if (psiFile instanceof PsiClassOwner) {
packageName = ((PsiClassOwner)psiFile).getPackageName();
} else {
packageName = null;
}
}
final boolean toDifferentPackage = !Comparing.strEqual(targetPackage.getQualifiedName(), packageName);
for (final PsiMethod abstractMethod : abstractMethods) {
final boolean toDifferentPackage =
!Comparing.strEqual(targetPackage.getQualifiedName(), StringUtil.getPackageName(subclass.getQualifiedName()));
abstractMethod.accept(new ClassMemberReferencesVisitor(subclass) {
@Override
protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) {
@@ -21,7 +21,6 @@
package com.intellij.refactoring.move.moveMembers;
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
import com.intellij.lang.LanguageExtension;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
@@ -282,7 +281,7 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
if (!JavaResolveUtil.isAccessible(member, myTargetClass, modifierListCopies.get(member), element, accessObjectClass, null)) {
newVisibility = newVisibility == null ? VisibilityUtil.getVisibilityStringToDisplay(member) : newVisibility;
String message =
CommonRefactoringUtil.capitalize(RefactoringBundle.message("0.with.1.visibility.is.not.accesible.from.2", RefactoringUIUtil.getDescription(member, false),
CommonRefactoringUtil.capitalize(RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2", RefactoringUIUtil.getDescription(member, false),
newVisibility, RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true)));
conflicts.putValue(member, message);
}
@@ -427,7 +427,7 @@ public class JavaSafeDeleteProcessor implements SafeDeleteProcessorDelegate {
break;
}
}
if (!anyOverridingRefs && isMultipleInterfacesImplementation(overridingMethod, allElementsToDelete)) {
if (!anyOverridingRefs && isMultipleInterfacesImplementation(overridingMethod, originalMethod, allElementsToDelete)) {
anyOverridingRefs = true;
multipleInterfaceImplementations.add(overridingMethod);
}
@@ -468,10 +468,12 @@ public class JavaSafeDeleteProcessor implements SafeDeleteProcessorDelegate {
return validOverriding;
}
private static boolean isMultipleInterfacesImplementation(final PsiMethod method, final PsiElement[] allElementsToDelete) {
private static boolean isMultipleInterfacesImplementation(final PsiMethod method,
PsiMethod originalMethod,
final PsiElement[] allElementsToDelete) {
final PsiMethod[] methods = method.findSuperMethods();
for(PsiMethod superMethod: methods) {
if (ArrayUtil.find(allElementsToDelete, superMethod) < 0) {
if (ArrayUtil.find(allElementsToDelete, superMethod) < 0 && !MethodSignatureUtil.isSuperMethod(originalMethod, superMethod)) {
return true;
}
}
@@ -0,0 +1,30 @@
public class NestedGenericGoodCodeIsRed {
public void main( String[] args ) {
satisfiesAllOf(isPositive(), isEqualTo(10.9));
satisfiesAllOf(isPositive(), isEqualTo(10));
Number num = null;
satisfiesAllOf(isPositive(), isEqualTo(num));
this.<Number>satisfiesAllOf<error descr="'satisfiesAllOf(NestedGenericGoodCodeIsRed.Predicate<? super java.lang.Number>, NestedGenericGoodCodeIsRed.Predicate<? super java.lang.Number>)' in 'NestedGenericGoodCodeIsRed' cannot be applied to '(NestedGenericGoodCodeIsRed.Predicate<java.lang.Number>, NestedGenericGoodCodeIsRed.Predicate<java.lang.Integer>)'">(isPositive(), isEqualTo(10))</error>;
}
public interface Predicate<T> {
}
public <ALL> void satisfiesAllOf( Predicate<? super ALL> first, Predicate<? super ALL> second ) {
}
public <POSITIVE extends Number> Predicate<POSITIVE> isPositive() {
return null;
}
public <EQUALTO extends Number> Predicate<EQUALTO> isEqualTo( EQUALTO target ) {
return null;
}
}
@@ -0,0 +1,11 @@
// "Create Getter" "true"
public class Test {
Integer field;
public foo() {
getField();
}
public Integer getField() {
return field;
}
}
@@ -0,0 +1,7 @@
// "Create Getter" "true"
public class Test {
Integer field;
public foo() {
get<caret>Field();
}
}
@@ -1,2 +1,2 @@
<html><head> <style type="text/css"> #error { background-color: #eeeeee; margin-bottom: 10px; } </style></head><body><small><b><a href="psi_element://Idea4780"><code>Idea4780</code></a></b></small><PRE>public&nbsp;<a href="psi_element://java.lang.Object"><code>Object</code></a>&nbsp;<b>read</b>()
throws&nbsp;<a href="psi_element://java.io.IOException"><code>IOException</code></a></PRE><DD><DL><DT><b>Throws:</b><DD><a href="psi_element://java.io.EOFException"><code>EOFException</code></a> - if this source is already closed when the <code>read()</code> is called, or is closed during the <code>read()</code>. <DD><font color=red>InterruptedIOException</font> - if the reading thread is interrupted.<DD><a href="psi_element://java.io.IOException"><code>IOException</code></a> - if an I/O error occurs while reading. </DD></DL></DD></body></html>
throws&nbsp;<a href="psi_element://java.io.IOException"><code>IOException</code></a></PRE><DD><DL><DT><b>Throws:</b><DD><a href="psi_element://java.io.IOException"><code>IOException</code></a> - if an I/O error occurs while reading. <DD><a href="psi_element://java.io.EOFException"><code>EOFException</code></a> - if this source is already closed when the <code>read()</code> is called, or is closed during the <code>read()</code>. <DD><font color=red>InterruptedIOException</font> - if the reading thread is interrupted.</DD></DL></DD></body></html>
@@ -0,0 +1,9 @@
public class Super {
}
class Child extends Super {
}
class ChildChild extends Child {
}
@@ -0,0 +1,19 @@
public class Super {
void f<caret>oo() {
}
}
class Child extends Super {
void foo(){
super.foo();
System.out.println("do some staff");
}
}
class ChildChild extends Child {
void foo(){
super.foo();
System.out.println("here do smth else");
}
}
@@ -50,6 +50,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testExplicitMethodParameters1() throws Exception { doTest(false); }
public void testInferenceWithBounds() throws Exception {doTest(false);}
public void testInferenceWithSuperBounds() throws Exception {doTest(false);}
public void testInferenceWithUpperBoundPromotion() throws Exception {doTest(false);}
public void testVariance() throws Exception {doTest(false);}
public void testForeachTypes() throws Exception {doTest(false);}
public void testRawOverridingMethods() throws Exception {doTest(false);}
@@ -78,7 +78,7 @@ public class IntroduceParameterTest extends LightCodeInsightTestCase {
}
public void testThisSubstitutionInQualifier() throws Exception {
doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, false, false, false, false, "field <b><code>Test.i</code></b> is not accesible from method <b><code>XTest.n()</code></b>. Value for introduced parameter in that method call will be incorrect.");
doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, false, false, false, false, "field <b><code>Test.i</code></b> is not accessible from method <b><code>XTest.n()</code></b>. Value for introduced parameter in that method call will be incorrect.");
}
public void testFieldAccess() throws Exception {
@@ -24,10 +24,7 @@ import com.intellij.JavaTestUtil;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.refactoring.memberPullUp.PullUpConflictsUtil;
import com.intellij.refactoring.memberPullUp.PullUpHelper;
@@ -75,8 +72,10 @@ public class PullUpMultifileTest extends MultiFileTestCase {
memberInfo.setChecked(true);
membersToMove[0] = memberInfo;
final PsiDirectory targetDirectory = targetClass.getContainingFile().getContainingDirectory();
final PsiPackage targetPackage = targetDirectory != null ? JavaDirectoryService.getInstance().getPackage(targetDirectory) : null;
conflictsMap.putAllValues(
PullUpConflictsUtil.checkConflicts(membersToMove, srcClass, targetClass, null, null, new InterfaceContainmentVerifier() {
PullUpConflictsUtil.checkConflicts(membersToMove, srcClass, targetClass, targetPackage, targetDirectory, new InterfaceContainmentVerifier() {
public boolean checkedInterfacesContain(PsiMethod psiMethod) {
return PullUpHelper.checkedInterfacesContain(Arrays.asList(membersToMove), psiMethod);
}
@@ -82,6 +82,11 @@ public class SafeDeleteTest extends MultiFileTestCase {
doTest("Super");
}
public void testMethodDeepHierarchy() throws Exception {
myDoCompare = false;
doTest("Super");
}
public void testLocalVariableSideEffect() throws Exception {
myDoCompare = false;
try {
@@ -159,11 +159,15 @@ public class ModuleRootsExternalizationTest extends ModuleTestCase {
"<orderEntry type=\"module-library\">" +
"<library>" +
"<CLASSES><root url=\"file://$MODULE_DIR$/unnamedLibClasses\" /></CLASSES>" +
"<JAVADOC />" +
"<SOURCES />" +
"</library>" +
"</orderEntry>" +
"<orderEntry type=\"module-library\">" +
"<library name=\"namedLibrary\">" +
"<CLASSES><root url=\"file://$MODULE_DIR$/namedLibClasses\" /></CLASSES>" +
"<JAVADOC />" +
"<SOURCES />" +
"</library>" +
"</orderEntry>" +
"</root>", module);
@@ -47,7 +47,7 @@ public class LibraryTest extends IdeaTestCase {
final Element element = new Element("root");
library.writeExternal(element);
assertEquals("<root><library name=\"library\"><CLASSES><root url=\"file://x.jar\" /></CLASSES><SOURCES><root url=\"file://x-src.jar\" /></SOURCES></library></root>",
assertEquals("<root><library name=\"library\"><CLASSES><root url=\"file://x.jar\" /></CLASSES><JAVADOC /><SOURCES><root url=\"file://x-src.jar\" /></SOURCES></library></root>",
new XMLOutputter().outputString(element));
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@@ -16,17 +16,12 @@
package com.intellij.lang.jsp;
import com.intellij.lang.Language;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* @author ik
*/
public interface JspFileViewProvider extends JspxFileViewProvider {
@NotNull
Language getTemplateDataLanguage();
Set<String> getKnownTaglibPrefixes();
}
@@ -32,8 +32,12 @@ public interface BaseJspFile extends XmlFile {
boolean isTagPage();
XmlTag[] getDirectiveTags(JspDirectiveKind directiveKind, final boolean searchInIncludes);
XmlTag createDirective(XmlTag context, JspDirectiveKind page);
XmlTag createDirective(XmlTag context, JspDirectiveKind directiveKind);
/**
* Method with a bad name. Returns file corresponding to getTemplateDataLanguage() method of ViewProvider
* @see com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider#getTemplateDataLanguage()
*/
PsiFile getBaseLanguageRoot();
/**
* @return file which the errorPage directive references,
@@ -43,4 +47,4 @@ public interface BaseJspFile extends XmlFile {
@NotNull
JspxFileViewProvider getViewProvider();
}
}
@@ -53,6 +53,13 @@ public interface TemplateBuilder {
*/
void replaceRange(TextRange rangeWithinElement, String replacementText);
/**
* Creates a replacement box for the specified text range within the container element.
* @param rangeWithinElement range within the container element.
* @param expression the replacement expression.
*/
public void replaceRange(TextRange rangeWithinElement, Expression expression);
/**
* Shows the live template and initiates editing process.
*/
@@ -59,6 +59,10 @@ public class DefaultRefactoringSupportProvider implements RefactoringSupportProv
return null;
}
public RefactoringActionHandler getExtractInterfaceHandler() {
return null;
}
public RefactoringActionHandler getExtractModuleHandler() {
return null;
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
@@ -38,7 +39,7 @@ public abstract class InlineActionHandler {
return canInlineElement(element);
}
public boolean isEnabledOnElement(PsiElement element, Editor editor) {
public boolean isEnabledOnElement(PsiElement element, @Nullable Editor editor) {
return isEnabledOnElement(element);
}
@@ -80,6 +80,12 @@ public interface RefactoringSupportProvider {
*/
@Nullable RefactoringActionHandler getPushDownHandler();
/**
* @return handler for extracting members to an interface in this language
* @see com.intellij.refactoring.RefactoringActionHandler
*/
@Nullable RefactoringActionHandler getExtractInterfaceHandler();
/**
* @return handler for extracting members to some module in this language
* @see com.intellij.refactoring.RefactoringActionHandler
@@ -25,12 +25,14 @@ import org.jetbrains.annotations.NotNull;
public interface TemplateLanguageFileViewProvider extends FileViewProvider {
/**
* e.g. JSP
* @return instanceof {@link com.intellij.psi.templateLanguages.TemplateLanguage}
*/
@NotNull
Language getBaseLanguage();
/**
* e.g. HTML for JSP files
* @return not instanceof {@link com.intellij.lang.DependentLanguage}
*/
@NotNull
@@ -42,8 +42,4 @@ public class IFileElementType extends ILazyParseableElementType {
final PsiParser parser = LanguageParserDefinitions.INSTANCE.forLanguage(getLanguage()).createParser(project);
return parser.parse(this, builder).getFirstChildNode();
}
//public boolean isParsable(CharSequence buffer, final Project project) {
// return true;
//}
}
@@ -175,6 +175,26 @@ public class PsiTreeUtil {
return parents;
}
@Nullable public static <T extends PsiElement> T findChildOfType(@NotNull final PsiElement element, @NotNull final Class<T> aClass) {
return findChildOfType(element, aClass, true);
}
@Nullable public static <T extends PsiElement> T findChildOfType(@NotNull final PsiElement element, @NotNull final Class<T> aClass, final boolean strict) {
PsiElementProcessor.FindElement<PsiElement> processor = new PsiElementProcessor.FindElement<PsiElement>() {
@Override
public boolean execute(PsiElement each) {
if (strict && each == element) return true;
if (instanceOf(aClass, each)) {
return setFound(each);
}
return true;
}
};
PsiTreeUtil.processElements(element, processor);
return (T)processor.getFoundElement();
}
@Nullable public static <T extends PsiElement> T getChildOfType(@NotNull PsiElement element, @NotNull Class<T> aClass) {
for(PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()){
if (instanceOf(aClass, child)) return (T)child;
@@ -432,7 +432,7 @@ public class PsiUtilBase {
}
@Nullable
public static PsiElement getElementAtCaret(Editor editor) {
public static PsiElement getElementAtCaret(@NotNull Editor editor) {
Project project = editor.getProject();
if (project == null) return null;
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
@@ -32,8 +32,8 @@ public interface NameSuggestionProvider {
ExtensionPointName<NameSuggestionProvider> EP_NAME = ExtensionPointName.create("com.intellij.nameSuggestionProvider");
@Nullable
SuggestedNameInfo getSuggestedNames(PsiElement element, PsiElement nameSuggestionContext, Set<String> result);
SuggestedNameInfo getSuggestedNames(PsiElement element, @Nullable PsiElement nameSuggestionContext, Set<String> result);
@Nullable
Collection<LookupElement> completeName(PsiElement element, final PsiElement nameSuggestionContext, final String prefix);
Collection<LookupElement> completeName(PsiElement element, @Nullable final PsiElement nameSuggestionContext, final String prefix);
}
@@ -204,7 +204,7 @@ public class CompletionData {
return null;
}
public static String findPrefixStatic(final PsiElement insertedElement, final int offsetInFile) {
public static String findPrefixStatic(final PsiElement insertedElement, final int offsetInFile, ElementPattern<Character> prefixStartTrim) {
if(insertedElement == null) return "";
final String prefix = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@@ -221,7 +221,11 @@ public class CompletionData {
return CompletionUtil.findJavaIdentifierPrefix(insertedElement, offsetInFile);
}
return findPrefixDefault(insertedElement, offsetInFile, not(character().javaIdentifierPart()));
return findPrefixDefault(insertedElement, offsetInFile, prefixStartTrim);
}
public static String findPrefixStatic(final PsiElement insertedElement, final int offsetInFile) {
return findPrefixStatic(insertedElement, offsetInFile, not(character().javaIdentifierPart()));
}
protected static String findPrefixDefault(final PsiElement insertedElement, final int offset, @NotNull final ElementPattern trimStart) {
@@ -149,13 +149,15 @@ public class EnterHandler extends BaseEnterHandler {
private static boolean isCommentComplete(PsiComment comment, CodeDocumentationAwareCommenter commenter) {
String commentText = comment.getText();
final String expectedCommentEnd = isDocComment(comment, commenter) ? commenter.getDocumentationCommentSuffix():commenter.getBlockCommentSuffix();
final boolean docComment = isDocComment(comment, commenter);
final String expectedCommentEnd = docComment ? commenter.getDocumentationCommentSuffix():commenter.getBlockCommentSuffix();
if (!commentText.endsWith(expectedCommentEnd)) return false;
final PsiFile containingFile = comment.getContainingFile();
final Language language = comment.getParent().getLanguage();
Lexer lexer = LanguageParserDefinitions.INSTANCE.forLanguage(language).createLexer(containingFile.getProject());
lexer.start(commentText, commenter.getDocumentationCommentPrefix().length(), commentText.length());
final String commentPrefix = docComment? commenter.getDocumentationCommentPrefix() : commenter.getBlockCommentPrefix();
lexer.start(commentText, commentPrefix == null? 0 : commentPrefix.length(), commentText.length());
QuoteHandler fileTypeHandler = TypedHandler.getQuoteHandler(containingFile);
JavaLikeQuoteHandler javaLikeQuoteHandler = fileTypeHandler instanceof JavaLikeQuoteHandler ?
(JavaLikeQuoteHandler)fileTypeHandler:null;
@@ -282,13 +282,13 @@ public class TypedHandler implements TypedActionHandler {
if (!iterator.atEnd()) {
iterator.advance();
IElementType tokenType = iterator.atEnd() ? null : iterator.getTokenType();
if (!BraceMatchingUtil.isPairedBracesAllowedBeforeTypeInFileType(braceTokenType, tokenType, fileType)) {
return;
}
if (!iterator.atEnd() && BraceMatchingUtil.isLBraceToken(iterator, fileText, fileType)) {
return;
if (!iterator.atEnd()) {
if (!BraceMatchingUtil.isPairedBracesAllowedBeforeTypeInFileType(braceTokenType, iterator.getTokenType(), fileType)) {
return;
}
if (BraceMatchingUtil.isLBraceToken(iterator, fileText, fileType)) {
return;
}
}
iterator.retreat();
@@ -393,8 +393,9 @@ public class TypedHandler implements TypedActionHandler {
int offset = editor.getCaretModel().getOffset();
CharSequence chars = editor.getDocument().getCharsSequence();
int length = editor.getDocument().getTextLength();
final Document document = editor.getDocument();
CharSequence chars = document.getCharsSequence();
int length = document.getTextLength();
if (isTypingEscapeQuote(editor, quoteHandler, offset)) return false;
if (offset < length && chars.charAt(offset) == quote){
@@ -424,7 +425,10 @@ public class TypedHandler implements TypedActionHandler {
if (isOpeningQuote(editor, quoteHandler, offset - 1) &&
hasNonClosedLiterals(editor, quoteHandler, offset - 1)) {
editor.getDocument().insertString(offset, String.valueOf(quote));
if (offset == document.getTextLength() ||
!Character.isUnicodeIdentifierPart(document.getCharsSequence().charAt(offset))) { //any better heuristic or an API?
document.insertString(offset, String.valueOf(quote));
}
}
return true;
@@ -401,9 +401,10 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
@Nullable
private static PsiElement resolve(final PsiReference ref) {
PsiElement resolvedElement = null;
// IDEA-56727 try resolve first as in GotoDeclarationAction
PsiElement resolvedElement = ref.resolve();
if (ref instanceof PsiPolyVariantReference) {
if (resolvedElement == null && ref instanceof PsiPolyVariantReference) {
final ResolveResult[] psiElements = ((PsiPolyVariantReference)ref).multiResolve(false);
if (psiElements.length > 0) {
final ResolveResult resolveResult = psiElements[0];
@@ -412,9 +413,6 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
}
}
}
else {
resolvedElement = ref.resolve();
}
return resolvedElement;
}
@@ -123,6 +123,12 @@ public class TemplateBuilderImpl implements TemplateBuilder {
myElements.add(key);
}
public void replaceRange(TextRange rangeWithinElement, Expression expression) {
final RangeMarker key = myDocument.createRangeMarker(rangeWithinElement);
myExpressions.put(key, expression);
myElements.add(key);
}
/**
* Adds end variable after the specified element
*/
@@ -28,6 +28,7 @@ import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.actions.EditorActionUtil;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
@@ -109,8 +110,10 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
myEditorDocument = editorFactory.createDocument("");
setLanguage(language);
myConsoleEditor = (EditorEx)editorFactory.createEditor(myEditorDocument, myProject);
myConsoleEditor.setBackgroundColor(myConsoleEditor.getColorsScheme().getColor(ConsoleViewContentType.CONSOLE_BACKGROUND_KEY));
myCurrentEditor = myConsoleEditor;
myHistoryViewer = (EditorEx)editorFactory.createViewer(((EditorFactoryImpl)editorFactory).createDocument(true), myProject);
myHistoryViewer.setBackgroundColor(myHistoryViewer.getColorsScheme().getColor(ConsoleViewContentType.CONSOLE_BACKGROUND_KEY));
myPanel.add(myHistoryViewer.getComponent(), BorderLayout.NORTH);
myPanel.add(myConsoleEditor.getComponent(), BorderLayout.CENTER);
setupComponents();
@@ -66,27 +66,6 @@ public abstract class PsiFileBase extends PsiFileImpl {
return myLanguage;
}
protected final FileElement createFileElement(final CharSequence docText) {
//final ParserDefinition parserDefinition = myLanguage.getParserDefinition();
//if (parserDefinition != null && parserDefinition.createParser(getProject()) != PsiUtil.NULL_PARSER) {
// return _createFileElement(docText, myLanguage, getProject(), parserDefinition);
//}
return super.createFileElement(docText);
}
//private static FileElement _createFileElement(final CharSequence docText,
// final Language language,
// Project project,
// final ParserDefinition parserDefinition) {
// final PsiParser parser = parserDefinition.createParser(project);
// final IElementType root = parserDefinition.getFileNodeType();
// final PsiBuilderImpl builder = new PsiBuilderImpl(language, project, null, docText);
// final FileElement fileRoot = (FileElement)parser.parse(root, builder);
// LOG.assertTrue(fileRoot.getElementType() == root,
// "Parsing file text returns rootElement with type different from declared in parser definition");
// return fileRoot;
//}
public void accept(@NotNull PsiElementVisitor visitor) {
visitor.visitFile(this);
}
@@ -230,7 +230,8 @@ public class PsiElement2UsageTargetAdapter implements PsiElementUsageTarget, Typ
}
public Icon getIcon(boolean open) {
return open ? myIconOpen.getIcon() : myIconClosed.getIcon();
final ComputableIcon computableIcon = open ? myIconOpen : myIconClosed;
return computableIcon == null? null : computableIcon.getIcon();
}
}
}
@@ -85,6 +85,7 @@ import java.util.regex.Pattern;
public class FindInProjectUtil {
private static final int USAGES_LIMIT = 1000;
private static final int USAGES_PER_READ_ACTION = 100;
private static final int FILES_SIZE_LIMIT = 70 * 1024 * 1024; // megabytes.
private static final int SINGLE_FILE_SIZE_LIMIT = 5 * 1024 * 1024; // megabytes.
@@ -218,7 +219,7 @@ public class FindInProjectUtil {
int i = 0;
long totalFilesSize = 0;
int count = 0;
boolean warningShown = false;
final boolean[] warningShown = new boolean[] {false};
final UsageViewManager usageViewManager = UsageViewManager.getInstance(project);
for (final PsiFile psiFile : psiFiles) {
@@ -252,22 +253,16 @@ public class FindInProjectUtil {
progress.setText2(FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count));
}
int countInFile = processUsagesInFile(psiFile, findModel, consumer);
int countInFile = processUsagesInFile(psiFile, findModel, consumer, count, warningShown);
if (countInFile > 0) {
totalFilesSize += fileLength;
if (totalFilesSize > FILES_SIZE_LIMIT && !warningShown) {
if (totalFilesSize > FILES_SIZE_LIMIT && !warningShown[0]) {
showTooManyUsagesWaring(project, FindBundle.message("find.excessive.total.size.prompt", presentableSize(totalFilesSize),
ApplicationNamesInfo.getInstance().getProductName()));
warningShown = true;
warningShown[0] = true;
}
}
count += countInFile;
if (count > USAGES_LIMIT && !warningShown) {
showTooManyUsagesWaring(project, FindBundle.message("find.excessive.usage.count.prompt", count));
warningShown = true;
}
}
if (!largeFiles.isEmpty()) {
@@ -317,22 +312,37 @@ public class FindInProjectUtil {
}
}
private static int processUsagesInFile(final PsiFile psiFile, final FindModel findModel, final Processor<UsageInfo> consumer) {
return ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
public Integer compute() {
if (psiFile.isValid()) {
VirtualFile virtualFile = psiFile.getVirtualFile();
// Check once more if valid and text since we're in new read action and things might have been changed.
if (FileTypeManager.getInstance().getFileTypeByFile(virtualFile).isBinary()) return 0; // do not decompile .class files
final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document != null) {
return addToUsages(document, consumer, findModel, psiFile);
}
private static int processUsagesInFile(final PsiFile psiFile,
final FindModel findModel,
final Processor<UsageInfo> consumer,
int alreadyCounted,
boolean[] warningShown) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile == null) return 0;
if (FileTypeManager.getInstance().getFileTypeByFile(virtualFile).isBinary()) return 0; // do not decompile .class files
final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document == null) return 0;
final int[] offset = new int[] {0};
int count = 0;
int found;
do {
found = ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
@Override
@NotNull
public Integer compute() {
if (!psiFile.isValid()) return 0;
return addToUsages(document, consumer, findModel, psiFile, offset, USAGES_PER_READ_ACTION);
}
return 0;
});
count += found;
if (found > 0 && count + alreadyCounted > USAGES_LIMIT && !warningShown[0]) {
showTooManyUsagesWaring(psiFile.getProject(), FindBundle.message("find.excessive.usage.count.prompt", count));
warningShown[0] = true;
}
}).intValue();
}
while (found != 0);
return count;
}
private static String getPresentablePath(final VirtualFile virtualFile) {
@@ -605,12 +615,11 @@ public class FindInProjectUtil {
}
private static int addToUsages(@NotNull Document document, @NotNull Processor<UsageInfo> consumer, @NotNull FindModel findModel,
@NotNull final PsiFile psiFile) {
@NotNull final PsiFile psiFile, int[] offsetRef, int maxUsages) {
int count = 0;
CharSequence text = document.getCharsSequence();
int textLength = document.getTextLength();
int offset = 0;
int offset = offsetRef[0];
Project project = psiFile.getProject();
@@ -632,7 +641,11 @@ public class FindInProjectUtil {
// for regular expr the size of the match could be zero -> could be infinite loop in finding usages!
++offset;
}
if (maxUsages > 0 && count >= maxUsages) {
break;
}
}
offsetRef[0] = offset;
return count;
}
@@ -80,7 +80,7 @@ class CustomFileTypeBraceMatcher implements BraceMatcher {
}
public boolean isPairedBracesAllowedBeforeType(@NotNull final IElementType lbraceType, @Nullable final IElementType contextType) {
return true;
return contextType == CustomHighlighterTokenType.WHITESPACE;
}
public int getCodeConstructStart(final PsiFile file, final int openingBraceOffset) {
@@ -73,7 +73,7 @@ class CustomFileTypeQuoteHandler implements QuoteHandler {
iterator.advance();
}
} finally {
while(iterator.getStart() != offset) iterator.retreat();
while (!iterator.atEnd() && iterator.getStart() != offset) iterator.retreat();
}
return false;
@@ -33,6 +33,7 @@ import com.intellij.ide.scopeView.nodes.BasePsiNode;
import com.intellij.ide.util.DeleteHandler;
import com.intellij.ide.util.DirectoryChooserUtil;
import com.intellij.ide.util.EditorHelper;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
@@ -419,7 +420,7 @@ public class ScopeTreeViewPanel extends JPanel implements JDOMExternalizable, Di
}
private void processNodeCreation(final PsiElement psiElement) {
if (psiElement instanceof PsiFile) {
if (psiElement instanceof PsiFile && !isInjected((PsiFile)psiElement)) {
reload(myBuilder.addFileNode((PsiFile)psiElement));
}
else if (psiElement instanceof PsiDirectory) {
@@ -433,7 +434,7 @@ public class ScopeTreeViewPanel extends JPanel implements JDOMExternalizable, Di
public void beforeChildRemoval(final PsiTreeChangeEvent event) {
final PsiElement child = event.getChild();
final PsiElement parent = event.getParent();
if (parent instanceof PsiDirectory && (child instanceof PsiFile || child instanceof PsiDirectory)) {
if (parent instanceof PsiDirectory && (child instanceof PsiFile && !isInjected((PsiFile)child) || child instanceof PsiDirectory)) {
queueUpdate(new Runnable() {
public void run() {
collapseExpand(myBuilder.removeNode(child, (PsiDirectory)parent));
@@ -447,7 +448,7 @@ public class ScopeTreeViewPanel extends JPanel implements JDOMExternalizable, Di
final PsiElement newParent = event.getNewParent();
final PsiElement child = event.getChild();
if (oldParent instanceof PsiDirectory && newParent instanceof PsiDirectory) {
if (child instanceof PsiFile) {
if (child instanceof PsiFile && !isInjected((PsiFile)child)) {
final PsiFile file = (PsiFile)child;
queueUpdate(new Runnable() {
public void run() {
@@ -470,7 +471,7 @@ public class ScopeTreeViewPanel extends JPanel implements JDOMExternalizable, Di
final PsiElement parent = event.getParent();
final PsiFile file = parent.getContainingFile();
if (file != null && file.getFileType() == StdFileTypes.JAVA) {
if (!file.getViewProvider().isPhysical()) return;
if (!file.getViewProvider().isPhysical() && !isInjected(file)) return;
queueUpdate(new Runnable() {
public void run() {
if (file.isValid()) {
@@ -505,7 +506,7 @@ public class ScopeTreeViewPanel extends JPanel implements JDOMExternalizable, Di
final NamedScope scope = getCurrentScope();
final PsiElement element = event.getNewChild();
final PsiFile psiFile = event.getFile();
if (psiFile != null) {
if (psiFile != null && !isInjected(psiFile)) {
if (psiFile.getLanguage() == psiFile.getViewProvider().getBaseLanguage()) {
queueUpdate(new Runnable() {
public void run() {
@@ -519,6 +520,10 @@ public class ScopeTreeViewPanel extends JPanel implements JDOMExternalizable, Di
}
}
private boolean isInjected(PsiFile psiFile) {
return InjectedLanguageManager.getInstance(myProject).isInjectedFragment(psiFile);
}
private void queueRefreshScope(final NamedScope scope) {
myUpdateQueue.cancelAllUpdates();
queueUpdate(new Runnable() {
@@ -20,24 +20,18 @@ import com.intellij.application.options.PathMacrosImpl;
import com.intellij.application.options.ReplacePathToMacroMap;
import com.intellij.openapi.components.ExpandMacroToPathMap;
import com.intellij.openapi.components.PathMacroMap;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.io.File;
public class ModulePathMacroManager extends BasePathMacroManager /*ProjectPathMacroManager*/ {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.ModulePathMacroManager");
public class ModulePathMacroManager extends BasePathMacroManager {
private final Module myModule;
public ModulePathMacroManager(final Module module) {
//super((ProjectEx) module.getProject());
myModule = module;
}
@@ -49,9 +43,14 @@ public class ModulePathMacroManager extends BasePathMacroManager /*ProjectPathMa
}
public ReplacePathToMacroMap getReplacePathMap() {
ReplacePathToMacroMap result = new ReplacePathToMacroMap();
result.putAll(super.getReplacePathMap());
getModuleHomeReplacements(result, true);
ReplacePathToMacroMap result = super.getReplacePathMap();
if (!myModule.isDisposed()) {
String projectDir = ProjectPathMacroManager.getProjectDir(myModule.getProject());
if (projectDir != null) {
projectDir = projectDir.replace('/', File.separatorChar);
}
addFileHierarchyReplacements(result, PathMacrosImpl.MODULE_DIR_MACRO_NAME, getModuleDir(myModule.getModuleFilePath()), projectDir);
}
return result;
}
@@ -76,39 +75,6 @@ public class ModulePathMacroManager extends BasePathMacroManager /*ProjectPathMa
result.put(s, path);
}
private void getModuleHomeReplacements(@NonNls ReplacePathToMacroMap result, final boolean addRelativePathMacros) {
String moduleDir = myModule.isDisposed() ? null : getModuleDir(myModule.getModuleFilePath());
if (moduleDir == null) return;
File f = new File(moduleDir.replace('/', File.separatorChar));
// [dsl]: Q?
//if(!f.exists()) return;
String macro = "$" + PathMacrosImpl.MODULE_DIR_MACRO_NAME + "$";
boolean check = false;
while (f != null && f.getParentFile() != null) {
@NonNls String path = PathMacroMap.quotePath(f.getAbsolutePath());
String s = macro;
if (StringUtil.endsWithChar(path, '/')) s += "/";
putIfAbsent(result, "file://" + path, "file://" + s, check);
putIfAbsent(result, "file:/" + path, "file:/" + s, check);
putIfAbsent(result, "file:" + path, "file:" + s, check);
putIfAbsent(result, "jar://" + path, "jar://" + s, check);
putIfAbsent(result, "jar:/" + path, "jar:/" + s, check);
putIfAbsent(result, "jar:" + path, "jar:" + s, check);
if (!path.equalsIgnoreCase("e:/") && !path.equalsIgnoreCase("r:/") && !path.equalsIgnoreCase("p:/")) {
putIfAbsent(result, path, s, check);
}
if (!addRelativePathMacros) break;
macro += "/..";
check = true;
f = f.getParentFile();
}
}
@Nullable
private String getModuleDir(String moduleFilePath) {
File moduleDirFile = new File(moduleFilePath).getParentFile();
@@ -20,6 +20,8 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.ContainerUtil;
@@ -43,8 +45,21 @@ public class LibraryRuntimeClasspathScope extends GlobalSearchScope {
super(project);
myModules = modules;
myIndex = ProjectRootManager.getInstance(project).getFileIndex();
final Set<Sdk> processedSdk = new THashSet<Sdk>();
final Set<Library> processedLibraries = new THashSet<Library>();
final Set<Module> processedModules = new THashSet<Module>();
final Condition<OrderEntry> condition = new Condition<OrderEntry>() {
@Override
public boolean value(OrderEntry orderEntry) {
if (orderEntry instanceof ModuleOrderEntry) {
final Module module = ((ModuleOrderEntry)orderEntry).getModule();
return module != null && processedModules.add(module);
}
return true;
}
};
for (Module module : modules) {
buildEntries(module);
buildEntries(module, processedModules, processedLibraries, processedSdk, condition);
}
}
@@ -60,13 +75,20 @@ public class LibraryRuntimeClasspathScope extends GlobalSearchScope {
return that.myModules.equals(myModules);
}
private void buildEntries(@NotNull final Module module) {
final Set<Sdk> myJDKProcessed = new THashSet<Sdk>();
private void buildEntries(@NotNull final Module module,
@NotNull final Set<Module> processedModules,
@NotNull final Set<Library> processedLibraries,
@NotNull final Set<Sdk> processedSdk,
Condition<OrderEntry> condition) {
if (!processedModules.add(module)) return;
ModuleRootManager.getInstance(module).orderEntries().recursively().process(new RootPolicy<LinkedHashSet<VirtualFile>>() {
ModuleRootManager.getInstance(module).orderEntries().recursively().satisfying(condition).process(new RootPolicy<LinkedHashSet<VirtualFile>>() {
public LinkedHashSet<VirtualFile> visitLibraryOrderEntry(final LibraryOrderEntry libraryOrderEntry,
final LinkedHashSet<VirtualFile> value) {
ContainerUtil.addAll(value, libraryOrderEntry.getRootFiles(OrderRootType.CLASSES));
final Library library = libraryOrderEntry.getLibrary();
if (library != null && processedLibraries.add(library)) {
ContainerUtil.addAll(value, libraryOrderEntry.getRootFiles(OrderRootType.CLASSES));
}
return value;
}
@@ -77,8 +99,10 @@ public class LibraryRuntimeClasspathScope extends GlobalSearchScope {
}
public LinkedHashSet<VirtualFile> visitJdkOrderEntry(final JdkOrderEntry jdkOrderEntry, final LinkedHashSet<VirtualFile> value) {
if (!myJDKProcessed.add(jdkOrderEntry.getJdk())) return value;
ContainerUtil.addAll(value, jdkOrderEntry.getRootFiles(OrderRootType.CLASSES));
final Sdk jdk = jdkOrderEntry.getJdk();
if (jdk != null && processedSdk.add(jdk)) {
ContainerUtil.addAll(value, jdkOrderEntry.getRootFiles(OrderRootType.CLASSES));
}
return value;
}
}, myEntries);
@@ -277,7 +277,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx {
if (roots.size() == 0 && rootType.skipWriteIfEmpty()) continue; //compatibility iml/ipr
final Element rootTypeElement = new Element(rootType.name());
roots.writeExternal(rootTypeElement, ROOT_PATH_ELEMENT);
if (rootTypeElement.getAttributes().size() > 0 || rootTypeElement.getContent().size() > 0) element.addContent(rootTypeElement);
element.addContent(rootTypeElement);
}
List<String> urls = new ArrayList<String>(myJarDirectories.keySet());
Collections.sort(urls, new Comparator<String>() {
@@ -199,19 +199,23 @@ public class ClasspathStorage implements StateStorage {
}
public Collection<IFile> getStorageFilesToSave() throws StateStorageException {
return needsSave() ? getAllStorageFiles() : Collections.<IFile>emptyList();
if (needsSave()) {
final List<IFile> list = new ArrayList<IFile>();
final ArrayList<VirtualFile> virtualFiles = new ArrayList<VirtualFile>();
getFileSet().listModifiedFiles(virtualFiles);
convert2Io(list, virtualFiles);
return list;
}
else {
return Collections.emptyList();
}
}
public List<IFile> getAllStorageFiles() {
final List<IFile> list = new ArrayList<IFile>();
final ArrayList<VirtualFile> virtualFiles = new ArrayList<VirtualFile>();
getFileSet().listFiles(virtualFiles);
for (VirtualFile virtualFile : virtualFiles) {
final File ioFile = VfsUtil.virtualToIoFile(virtualFile);
list.add(FileSystem.FILE_SYSTEM.createFile(ioFile.getAbsolutePath()));
}
convert2Io(list, virtualFiles);
return list;
}
};
@@ -220,6 +224,13 @@ public class ClasspathStorage implements StateStorage {
return session;
}
private static void convert2Io(List<IFile> list, ArrayList<VirtualFile> virtualFiles) {
for (VirtualFile virtualFile : virtualFiles) {
final File ioFile = VfsUtil.virtualToIoFile(virtualFile);
list.add(FileSystem.FILE_SYSTEM.createFile(ioFile.getAbsolutePath()));
}
}
public void finishSave(final SaveSession saveSession) {
try {
LOG.assertTrue(mySession == saveSession);
@@ -17,8 +17,10 @@
package com.intellij.openapi.roots.impl.storage;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.io.fs.IFile;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
public interface FileSet {
@@ -28,4 +30,5 @@ public interface FileSet {
void commit() throws IOException;
void listModifiedFiles(List<VirtualFile> list);
}
@@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable;
public class PsiReferenceProviderBean extends AbstractExtensionPointBean {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiReferenceProviderBean");
@Tag("className")
@Attribute("providerClass")
public String className;
@Tag("description")
public String description;
@@ -19,8 +19,11 @@ package com.intellij.psi.impl;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.Nullable;
import static com.intellij.util.ObjectUtils.*;
/**
* @author Dmitry Avdeev
*/
@@ -28,9 +28,12 @@ import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.ParameterizedCachedValueProvider;
import com.intellij.psi.util.ParameterizedCachedValue;
import com.intellij.psi.PsiManager;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.util.ObjectUtils.*;
public abstract class PsiParameterizedCachedValue<T,P> extends PsiCachedValue<T> implements ParameterizedCachedValue<T,P> {
private final ParameterizedCachedValueProvider<T,P> myProvider;
@@ -27,6 +27,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IFileElementType;
@@ -126,24 +127,37 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
};
}
private static Key<StubElement> stubElementKey = Key.create("stub.tree.for.file.content");
@Nullable
static StubElement buildStubTree(final FileContent inputData) {
final FileType fileType = inputData.getFileType();
public static StubElement buildStubTree(final FileContent inputData) {
StubElement data = inputData.getUserData(stubElementKey);
if (data != null) return data;
if (fileType.isBinary()) {
final BinaryFileStubBuilder builder = BinaryFileStubBuilders.INSTANCE.forFileType(fileType);
assert builder != null;
synchronized (inputData) {
data = inputData.getUserData(stubElementKey);
if (data != null) return data;
return builder.buildStubTree(inputData.getFile(), inputData.getContent(), inputData.getProject());
final FileType fileType = inputData.getFileType();
if (fileType.isBinary()) {
final BinaryFileStubBuilder builder = BinaryFileStubBuilders.INSTANCE.forFileType(fileType);
assert builder != null;
data = builder.buildStubTree(inputData.getFile(), inputData.getContent(), inputData.getProject());
} else {
final LanguageFileType filetype = (LanguageFileType)fileType;
Language l = filetype.getLanguage();
final IFileElementType type = LanguageParserDefinitions.INSTANCE.forLanguage(l).getFileNodeType();
PsiFile psi = inputData.getPsiFile();
data = ((IStubFileElementType)type).getBuilder().buildStubTree(psi);
}
inputData.putUserData(stubElementKey, data);
return data;
}
final LanguageFileType filetype = (LanguageFileType)fileType;
Language l = filetype.getLanguage();
final IFileElementType type = LanguageParserDefinitions.INSTANCE.forLanguage(l).getFileNodeType();
PsiFile psi = inputData.getPsiFile();
return ((IStubFileElementType)type).getBuilder().buildStubTree(psi);
}
public KeyDescriptor<Integer> getKeyDescriptor() {
@@ -14,41 +14,22 @@
* limitations under the License.
*/
package com.intellij.refactoring.actions;
import com.intellij.lang.refactoring.RefactoringSupportProvider;
import com.intellij.refactoring.RefactoringActionHandler;
import org.jetbrains.annotations.Nullable;
package com.intellij.execution.testframework;
import com.intellij.execution.ui.ConsoleViewContentType;
public class ExternalOutput implements Printable {
private final ConsoleViewContentType myType;
private final String myContents;
public ExternalOutput(final String contents, final ConsoleViewContentType type) {
myType = type;
myContents = contents;
public class ExtractInterfaceAction extends ExtractSuperActionBase {
public ExtractInterfaceAction() {
setInjectedContext(true);
}
public void printOn(final Printer printer) {
printer.print(myContents, myType);
@Nullable
@Override
protected RefactoringActionHandler getRefactoringHandler(RefactoringSupportProvider supportProvider) {
return supportProvider.getExtractInterfaceHandler();
}
}
}
@@ -13,19 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.refactoring.extractInterface;
import com.intellij.refactoring.actions.BaseExtractModuleAction;
import com.intellij.lang.Language;
import com.intellij.lang.java.JavaLanguage;
package com.intellij.refactoring.actions;
import com.intellij.lang.refactoring.RefactoringSupportProvider;
import com.intellij.refactoring.RefactoringActionHandler;
/**
* @author Dennis.Ushakov
*/
public class ExtractInterfaceAction extends BaseExtractModuleAction {
public class ExtractModuleAction extends ExtractSuperActionBase {
@Override
protected boolean isEnabledOnLanguage(Language language) {
return language instanceof JavaLanguage;
protected RefactoringActionHandler getRefactoringHandler(RefactoringSupportProvider supportProvider) {
return supportProvider.getExtractModuleHandler();
}
}
}
@@ -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.
@@ -25,8 +25,10 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.lang.ElementsHandler;
import org.jetbrains.annotations.Nullable;
public abstract class ExtractSuperActionBase extends BasePlatformRefactoringAction {
public abstract class BaseExtractModuleAction extends BaseRefactoringAction {
public boolean isAvailableInEditorOnly() {
return false;
}
@@ -34,24 +36,25 @@ public abstract class BaseExtractModuleAction extends BaseRefactoringAction {
public boolean isEnabledOnElements(PsiElement[] elements) {
if (elements.length > 0) {
final Language language = elements[0].getLanguage();
final RefactoringActionHandler handler = LanguageRefactoringSupport.INSTANCE.forLanguage(language).getExtractModuleHandler();
return isEnabledOnLanguage(language) && handler instanceof ElementsHandler && ((ElementsHandler)handler).isEnabledOnElements(elements);
final RefactoringActionHandler handler = getRefactoringHandler(LanguageRefactoringSupport.INSTANCE.forLanguage(language));
return handler instanceof ElementsHandler && ((ElementsHandler)handler).isEnabledOnElements(elements);
}
return false;
}
public RefactoringActionHandler getHandler(DataContext dataContext) {
PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
if (file == null) return null;
final RefactoringSupportProvider supportProvider = LanguageRefactoringSupport.INSTANCE.forLanguage(file.getViewProvider().getBaseLanguage());
return supportProvider != null ? supportProvider.getExtractModuleHandler() : null;
final RefactoringSupportProvider supportProvider =
LanguageRefactoringSupport.INSTANCE.forLanguage(file.getViewProvider().getBaseLanguage());
return supportProvider != null ? getRefactoringHandler(supportProvider) : null;
}
@Nullable
protected abstract RefactoringActionHandler getRefactoringHandler(RefactoringSupportProvider supportProvider);
protected boolean isAvailableForLanguage(final Language language) {
return isEnabledOnLanguage(language) &&
LanguageRefactoringSupport.INSTANCE.forLanguage(language).getExtractModuleHandler() != null;
return getRefactoringHandler(LanguageRefactoringSupport.INSTANCE.forLanguage(language)) != null;
}
protected abstract boolean isEnabledOnLanguage(final Language language);
}
@@ -16,38 +16,12 @@
package com.intellij.refactoring.actions;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageRefactoringSupport;
import com.intellij.lang.refactoring.RefactoringSupportProvider;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.lang.ElementsHandler;
public class ExtractSuperclassAction extends BasePlatformRefactoringAction {
public boolean isAvailableInEditorOnly() {
return false;
}
public boolean isEnabledOnElements(PsiElement[] elements) {
if (elements.length > 0) {
final Language language = elements[0].getLanguage();
final RefactoringActionHandler handler = LanguageRefactoringSupport.INSTANCE.forLanguage(language).getExtractModuleHandler();
return handler instanceof ElementsHandler && ((ElementsHandler)handler).isEnabledOnElements(elements);
}
return false;
}
public RefactoringActionHandler getHandler(DataContext dataContext) {
PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
if (file == null) return null;
final RefactoringSupportProvider supportProvider = LanguageRefactoringSupport.INSTANCE.forLanguage(file.getViewProvider().getBaseLanguage());
return supportProvider != null ? supportProvider.getExtractSuperClassHandler() : null;
}
protected boolean isAvailableForLanguage(final Language language) {
return LanguageRefactoringSupport.INSTANCE.forLanguage(language).getExtractSuperClassHandler() != null;
public class ExtractSuperclassAction extends ExtractSuperActionBase {
@Override
protected RefactoringActionHandler getRefactoringHandler(RefactoringSupportProvider supportProvider) {
return supportProvider.getExtractSuperClassHandler();
}
}
@@ -128,6 +128,7 @@ public abstract class ExtractSuperBaseDialog<ClassType extends PsiElement, Membe
final ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(myRbExtractSuperclass);
buttonGroup.add(myRbExtractSubclass);
customizeRadiobuttons(box, buttonGroup);
myRbExtractSuperclass.setSelected(true);
ItemListener listener = new ItemListener() {
@@ -140,6 +141,9 @@ public abstract class ExtractSuperBaseDialog<ClassType extends PsiElement, Membe
return box;
}
protected void customizeRadiobuttons(Box box, ButtonGroup buttonGroup) {
}
protected JComponent createNorthPanel() {
Box box = Box.createVerticalBox();
@@ -50,7 +50,7 @@ public class ExtractIncludeDialog extends DialogWrapper {
private JTextField myNameField;
private final PsiDirectory myCurrentDirectory;
private static final String REFACTORING_NAME = RefactoringBundle.message("extractIncludeFile.name");
private final String myExtension;
protected final String myExtension;
protected JLabel myTargetDirLabel;
public PsiDirectory getTargetDirectory() {
@@ -60,7 +60,8 @@ public class ExtractIncludeDialog extends DialogWrapper {
private PsiDirectory myTargetDirectory;
public String getTargetFileName () {
return myNameField.getText().trim() + "." + myExtension;
String name = myNameField.getText().trim();
return name.contains(".") ? name: name + "." + myExtension;
}
public ExtractIncludeDialog(final PsiDirectory currentDirectory, final String extension) {
@@ -116,7 +117,7 @@ public class ExtractIncludeDialog extends DialogWrapper {
}
protected String getNameLabel() {
return RefactoringBundle.message("name.for.extracted.include.file");
return RefactoringBundle.message("name.for.extracted.include.file", myExtension);
}
private void validateOKButton() {
@@ -78,12 +78,11 @@ public class FileReferenceContextUtil {
if (!range.intersects(element.getTextRange())) return;
String text = element.getText();
PsiFileSystemItem item = map.get(text);
element = bindElement(element, item);
if (element != null) {
element.acceptChildren(this);
}
element.putCopyableUserData(REF_FILE_SYSTEM_ITEM_KEY, item);
element.acceptChildren(this);
}
});
decodeFileReferences(element);
}
private static PsiElement bindElement(PsiElement element, PsiFileSystemItem item) {
@@ -17,12 +17,18 @@
package com.intellij.refactoring.rename;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.StatusBarEx;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.impl.light.LightElement;
@@ -39,6 +45,7 @@ import com.intellij.refactoring.util.RelatedUsageInfo;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
@@ -46,6 +53,8 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.util.*;
public class RenameProcessor extends BaseRefactoringProcessor {
@@ -65,6 +74,7 @@ public class RenameProcessor extends BaseRefactoringProcessor {
private NonCodeUsageInfo[] myNonCodeUsages = new NonCodeUsageInfo[0];
private final List<AutomaticRenamerFactory> myRenamerFactories = new ArrayList<AutomaticRenamerFactory>();
private final List<AutomaticRenamer> myRenamers = new ArrayList<AutomaticRenamer>();
private final List<UnresolvableCollisionUsageInfo> mySkippedUsages = new ArrayList<UnresolvableCollisionUsageInfo>();
public RenameProcessor(Project project,
PsiElement element,
@@ -139,8 +149,6 @@ public class RenameProcessor extends BaseRefactoringProcessor {
return false;
}
}
Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(usagesIn));
RenameUtil.removeConflictUsages(usagesSet);
final List<UsageInfo> variableUsages = new ArrayList<UsageInfo>();
if (!myRenamers.isEmpty()) {
@@ -174,10 +182,13 @@ public class RenameProcessor extends BaseRefactoringProcessor {
}
}
if (!variableUsages.isEmpty()) {
usagesSet.addAll(variableUsages);
refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()]));
final Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(usagesIn));
usagesSet.addAll(variableUsages);
final List<UnresolvableCollisionUsageInfo> conflictUsages = RenameUtil.removeConflictUsages(usagesSet);
if (conflictUsages != null) {
mySkippedUsages.addAll(conflictUsages);
}
refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()]));
prepareSuccessful();
return true;
@@ -192,7 +203,7 @@ public class RenameProcessor extends BaseRefactoringProcessor {
final Runnable runnable = new Runnable() {
public void run() {
for (final AutomaticRenamer renamer : myRenamers) {
renamer.findUsages(variableUsages, mySearchInComments, mySearchTextOccurrences);
renamer.findUsages(variableUsages, mySearchInComments, mySearchTextOccurrences, mySkippedUsages);
}
}
};
@@ -326,6 +337,32 @@ public class RenameProcessor extends BaseRefactoringProcessor {
}
}
myNonCodeUsages = nonCodeUsages.toArray(new NonCodeUsageInfo[nonCodeUsages.size()]);
if (!mySkippedUsages.isEmpty()) {
if (!ApplicationManager.getApplication().isUnitTestMode() && !ApplicationManager.getApplication().isHeadlessEnvironment()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
final IdeFrame ideFrame = WindowManager.getInstance().getIdeFrame(myProject);
if (ideFrame != null) {
StatusBarEx statusBar = (StatusBarEx)ideFrame.getStatusBar();
HyperlinkListener listener = new HyperlinkListener() {
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) return;
Messages.showMessageDialog("<html>" +
StringUtil.join(mySkippedUsages, new Function<UnresolvableCollisionUsageInfo, String>() {
public String fun(UnresolvableCollisionUsageInfo unresolvableCollisionUsageInfo) {
return unresolvableCollisionUsageInfo.getDescription();
}
}, "<br>") +
"</html>", "Don't panic! They are safe to skip", null);
}
};
statusBar.notifyProgressByBalloon(MessageType.WARNING, "<html><body>Unable to rename certain usages. <a href=\"\">Browse</a></body></html>", null, listener);
}
}
}, ModalityState.NON_MODAL);
}
}
}
protected void performPsiSpoilingRefactoring() {
@@ -239,13 +239,17 @@ public class RenameUtil {
ref.handleElementRename(newName);
}
public static void removeConflictUsages(Set<UsageInfo> usages) {
@Nullable
public static List<UnresolvableCollisionUsageInfo> removeConflictUsages(Set<UsageInfo> usages) {
final List<UnresolvableCollisionUsageInfo> result = new ArrayList<UnresolvableCollisionUsageInfo>();
for (Iterator<UsageInfo> iterator = usages.iterator(); iterator.hasNext();) {
UsageInfo usageInfo = iterator.next();
if (usageInfo instanceof UnresolvableCollisionUsageInfo) {
result.add((UnresolvableCollisionUsageInfo)usageInfo);
iterator.remove();
}
}
return result.isEmpty() ? null : result;
}
public static void addConflictDescriptions(UsageInfo[] usages, MultiMap<PsiElement, String> conflicts) {
@@ -47,9 +47,16 @@ public abstract class AutomaticRenamer {
}
public void findUsages(List<UsageInfo> result, final boolean searchInStringsAndComments, final boolean searchInNonJavaFiles) {
findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, null);
}
public void findUsages(List<UsageInfo> result,
final boolean searchInStringsAndComments,
final boolean searchInNonJavaFiles,
List<UnresolvableCollisionUsageInfo> unresolvedUsages) {
for (Iterator<PsiNamedElement> iterator = myElements.iterator(); iterator.hasNext();) {
final PsiNamedElement variable = iterator.next();
final boolean success = findUsagesForElement(variable, result, searchInStringsAndComments, searchInNonJavaFiles);
final boolean success = findUsagesForElement(variable, result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages);
if (!success) {
iterator.remove();
}
@@ -59,12 +66,17 @@ public abstract class AutomaticRenamer {
private boolean findUsagesForElement(PsiNamedElement element,
List<UsageInfo> result,
final boolean searchInStringsAndComments,
final boolean searchInNonJavaFiles) {
final boolean searchInNonJavaFiles, List<UnresolvableCollisionUsageInfo> unresolvedUsages) {
final String newName = getNewName(element);
if (newName != null) {
final UsageInfo[] usages = RenameUtil.findUsages(element, newName, searchInStringsAndComments, searchInNonJavaFiles, myRenames);
for (final UsageInfo usage : usages) {
if (usage instanceof UnresolvableCollisionUsageInfo) return false;
if (usage instanceof UnresolvableCollisionUsageInfo) {
if (unresolvedUsages != null) {
unresolvedUsages.add((UnresolvableCollisionUsageInfo)usage);
}
return false;
}
}
ContainerUtil.addAll(result, usages);
}
@@ -25,7 +25,7 @@ import com.intellij.psi.ElementDescriptionProvider;
public class RefactoringDescriptionLocation extends ElementDescriptionLocation {
private final boolean myWithParent;
private RefactoringDescriptionLocation(boolean withParent) {
protected RefactoringDescriptionLocation(boolean withParent) {
myWithParent = withParent;
}
@@ -27,6 +27,7 @@ import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -45,11 +46,13 @@ public abstract class ProcessHandler extends UserDataHolderBase {
private final Semaphore myWaitSemaphore;
private final ProcessListener myEventMulticaster;
private final TasksRunner myAfterStartNotifiedRunner;
protected ProcessHandler() {
myEventMulticaster = createEventMulticaster();
myWaitSemaphore = new Semaphore();
myWaitSemaphore.down();
addProcessListener(myAfterStartNotifiedRunner = new TasksRunner());
}
public void startNotify() {
@@ -86,7 +89,7 @@ public abstract class ProcessHandler extends UserDataHolderBase {
}
public void destroyProcess() {
afterStartNotified(new Runnable() {
myAfterStartNotifiedRunner.execute(new Runnable() {
public void run() {
if (myState.compareAndSet(STATE_RUNNING, STATE_TERMINATING)) {
fireProcessWillTerminate(true);
@@ -97,7 +100,7 @@ public abstract class ProcessHandler extends UserDataHolderBase {
}
public void detachProcess() {
afterStartNotified(new Runnable() {
myAfterStartNotifiedRunner.execute(new Runnable() {
public void run() {
if (myState.compareAndSet(STATE_RUNNING, STATE_TERMINATING)) {
fireProcessWillTerminate(false);
@@ -132,7 +135,7 @@ public abstract class ProcessHandler extends UserDataHolderBase {
}
private void notifyTerminated(final int exitCode, final boolean willBeDestroyed) {
afterStartNotified(new Runnable() {
myAfterStartNotifiedRunner.execute(new Runnable() {
public void run() {
LOG.assertTrue(isStartNotified(), "Start notify is not called");
@@ -173,21 +176,6 @@ public abstract class ProcessHandler extends UserDataHolderBase {
myEventMulticaster.processWillTerminate(new ProcessEvent(this), willBeDestroyed);
}
private void afterStartNotified(final Runnable runnable) {
if (isStartNotified()) {
runnable.run();
}
else {
addProcessListener(new ProcessAdapter() {
public void startNotified(ProcessEvent event) {
removeProcessListener(this);
runnable.run();
}
});
assert !isStartNotified();
}
}
public boolean isStartNotified() {
return myState.get() > STATE_INITIAL;
}
@@ -208,4 +196,40 @@ public abstract class ProcessHandler extends UserDataHolderBase {
}
});
}
private final class TasksRunner extends ProcessAdapter {
private final List<Runnable> myPendingTasks = new ArrayList<Runnable>();
public void startNotified(ProcessEvent event) {
removeProcessListener(this);
// at this point it is guaranteed that nothing will be added to myPendingTasks
runPendingTasks();
}
public void execute(Runnable task) {
if (isStartNotified()) {
task.run();
}
else {
synchronized (myPendingTasks) {
myPendingTasks.add(task);
}
if (isStartNotified()) {
runPendingTasks();
}
}
}
private void runPendingTasks() {
final Runnable[] tasks;
synchronized (myPendingTasks) {
tasks = myPendingTasks.toArray(new Runnable[myPendingTasks.size()]);
myPendingTasks.clear();
}
for (Runnable task : tasks) {
task.run();
}
}
}
}
@@ -32,6 +32,13 @@ public abstract class PathMacros {
public abstract void setMacro(String name, String value);
/**
* Obsolete macros that are to be removed gently from the project files. They can be read, but not written again. Not persisted.
* @param name
* @param value
*/
public abstract void addLegacyMacro(@NotNull String name, @NotNull String value);
public abstract void removeMacro(String name);
public abstract Set<String> getUserMacroNames();
@@ -47,4 +54,6 @@ public abstract class PathMacros {
public abstract boolean isIgnoredMacroName(@NotNull final String macro);
public abstract void removeAllMacros();
public abstract Collection<String> getLegacyMacroNames();
}
@@ -658,8 +658,8 @@ public class VfsUtil {
}
@Nullable
public static VirtualFile createDirectoryIfMissing(@NotNull String dir) throws IOException {
return doCreateDirectoriesIfMissing(FileUtil.toSystemIndependentName(dir));
public static VirtualFile createDirectoryIfMissing(@NotNull String directoryPath) throws IOException {
return doCreateDirectoriesIfMissing(FileUtil.toSystemIndependentName(directoryPath));
}
private static VirtualFile doCreateDirectoriesIfMissing(String dir) throws IOException {
@@ -35,6 +35,7 @@ import java.util.List;
public class HyperlinkLabel extends HighlightableComponent {
private HighlightedText myHighlightedText;
private final List<HyperlinkListener> myListeners = new ArrayList<HyperlinkListener>();
private boolean myUseIconAsLink;
private final Color myTextForegroundColor;
private final Color myTextBackgroundColor;
private final Color myTextEffectColor;
@@ -62,6 +63,7 @@ public class HyperlinkLabel extends HighlightableComponent {
}
public void setHyperlinkText(String text) {
myUseIconAsLink = true;
setHyperlinkText("", text, "");
}
@@ -71,6 +73,10 @@ public class HyperlinkLabel extends HighlightableComponent {
adjustSize();
}
public void setUseIconAsLink(boolean useIconAsLink) {
myUseIconAsLink = useIconAsLink;
}
private void adjustSize() {
final Dimension preferredSize = this.getPreferredSize();
this.setMinimumSize(preferredSize);
@@ -96,6 +102,9 @@ public class HyperlinkLabel extends HighlightableComponent {
}
private boolean isOnLink(int x) {
if (myUseIconAsLink && myIcon != null && x < myIcon.getIconWidth()) {
return true;
}
return findRegionByX(x) != null;
}
@@ -22,7 +22,6 @@ import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
@@ -37,10 +36,6 @@ public class PathMacrosCollector extends PathMacroMap {
private final Matcher myMatcher;
private static final Set<String> ourSystemMacroNames = new HashSet<String>(
Arrays.asList(PathMacrosImpl.APPLICATION_HOME_MACRO_NAME, PathMacrosImpl.MODULE_DIR_MACRO_NAME, PathMacrosImpl.PROJECT_DIR_MACRO_NAME
//, PathMacrosImpl.USER_HOME_MACRO_NAME
));
private static final String FILE_PROTOCOL = "file:";
private static final String JAR_PROTOCOL = "jar:";
@@ -48,15 +43,12 @@ public class PathMacrosCollector extends PathMacroMap {
myMatcher = MACRO_PATTERN.matcher("");
}
public static Set<String> getMacroNames(Element root, @Nullable final NotNullFunction<Object, Boolean> filter) {
return getMacroNames(root, filter, null);
}
public static Set<String> getMacroNames(Element root, @Nullable final NotNullFunction<Object, Boolean> filter, @Nullable final NotNullFunction<Object, Boolean> recursiveFilter, @NotNull final PathMacros pathMacros) {
final PathMacrosCollector collector = new PathMacrosCollector();
collector.substitute(root, true, false, filter, recursiveFilter);
final HashSet<String> result = new HashSet<String>(collector.myMacroMap.keySet());
result.removeAll(ourSystemMacroNames);
result.removeAll(pathMacros.getSystemMacroNames());
result.removeAll(pathMacros.getLegacyMacroNames());
result.removeAll(PathMacrosImpl.getToolMacroNames());
result.removeAll(pathMacros.getIgnoredMacroNames());
return result;
@@ -39,6 +39,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
public class PathMacrosImpl extends PathMacros implements ApplicationComponent, NamedJDOMExternalizable, RoamingTypeDisabled {
private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.PathMacrosImpl");
private final Map<String,String> myLegacyMacros = new HashMap<String,String>();
private final Map<String,String> myMacros = new HashMap<String, String>();
private final JBReentrantReadWriteLock myLock = LockFactory.createReadWriteLock();
private final List<String> myIgnoredMacros = new CopyOnWriteArrayList<String>();
@@ -70,7 +71,7 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent,
ourSystemMacroNames.add(APPLICATION_HOME_MACRO_NAME);
ourSystemMacroNames.add(PROJECT_DIR_MACRO_NAME);
ourSystemMacroNames.add(MODULE_DIR_MACRO_NAME);
//ourSystemMacroNames.add(USER_HOME_MACRO_NAME);
ourSystemMacroNames.add(USER_HOME_MACRO_NAME);
}
private static final Set<String> ourToolsMacros = new HashSet<String>();
@@ -213,6 +214,17 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent,
}
}
@Override
public Collection<String> getLegacyMacroNames() {
try {
myLock.readLock().lock();
return myLegacyMacros.keySet();
}
finally {
myLock.readLock().unlock();
}
}
public void setMacro(@NotNull String name, @NotNull String value) {
if (value.trim().length() == 0) return;
try {
@@ -224,6 +236,18 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent,
}
}
@Override
public void addLegacyMacro(@NotNull String name, @NotNull String value) {
try {
myLock.writeLock().lock();
myLegacyMacros.put(name, value);
myMacros.remove(name);
}
finally {
myLock.writeLock().unlock();
}
}
public void removeMacro(String name) {
try {
myLock.writeLock().lock();
@@ -278,8 +302,7 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent,
}
public void addMacroReplacements(ReplacePathToMacroMap result) {
final Set<String> macroNames = getUserMacroNames();
for (final String name : macroNames) {
for (final String name : getUserMacroNames()) {
final String value = getValue(name);
if (value != null && value.trim().length() > 0) result.addMacroReplacement(value, name);
}
@@ -287,11 +310,20 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent,
public void addMacroExpands(ExpandMacroToPathMap result) {
final Set<String> macroNames = getUserMacroNames();
for (final String name : macroNames) {
for (final String name : getUserMacroNames()) {
final String value = getValue(name);
if (value != null && value.trim().length() > 0) result.addMacroExpand(name, value);
}
myLock.readLock().lock();
try {
for (Map.Entry<String, String> entry : myLegacyMacros.entrySet()) {
result.addMacroExpand(entry.getKey(), entry.getValue());
}
}
finally {
myLock.readLock().unlock();
}
}
}
@@ -37,16 +37,28 @@ public class ReplacePathToMacroMap extends PathMacroMap {
if (idx1 != idx2) return idx1 - idx2;
return o2.getKey().length() - o1.getKey().length();
return stripPrefix(o2.getKey()).length() - stripPrefix(o1.getKey()).length();
}
private int getIndex(final Map.Entry<String, String> s) {
if (s.getValue().indexOf("..") >= 0) return 3;
final String replacement = s.getValue();
if (replacement.indexOf("..") >= 0) return 3;
if (replacement.indexOf("$" + PathMacrosImpl.USER_HOME_MACRO_NAME + "$") >= 0) return 3;
if (s.getValue().indexOf("$MODULE_DIR$") >= 0) return 1;
if (s.getValue().indexOf("$PROJECT_DIR$") >= 0) return 1;
if (replacement.indexOf("$" + PathMacrosImpl.MODULE_DIR_MACRO_NAME + "$") >= 0) return 1;
if (replacement.indexOf("$" + PathMacrosImpl.PROJECT_DIR_MACRO_NAME + "$") >= 0) return 1;
return 2;
}
private String stripPrefix(String key) {
key = StringUtil.trimStart(key, "jar:");
key = StringUtil.trimStart(key, "file:");
while (key.startsWith("/")) {
key = key.substring(1);
}
return key;
}
};
@NonNls private static final String[] PROTOCOLS = new String[]{"file", "jar"};
@@ -19,7 +19,4 @@ package com.intellij.openapi.components.impl;
* @author mike
*/
public class ApplicationPathMacroManager extends BasePathMacroManager {
public ApplicationPathMacroManager() {
super(true);
}
}
@@ -20,33 +20,63 @@ import com.intellij.application.options.ReplacePathToMacroMap;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.ExpandMacroToPathMap;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.components.PathMacroMap;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.FactoryMap;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.*;
public class BasePathMacroManager extends PathMacroManager {
private PathMacrosImpl myPathMacros;
private boolean myUseUserMacroses;
protected static void addFileHierarchyReplacements(ReplacePathToMacroMap result,
String variableName,
@Nullable String _path, @Nullable String stopAt) {
if (_path == null) {
return;
}
public BasePathMacroManager(boolean useUserMacroses) {
myUseUserMacroses = useUserMacroses;
}
String macro = "$" + variableName + "$";
File dir = new File(_path.replace('/', File.separatorChar));
boolean check = false;
while (dir != null && dir.getParentFile() != null) {
@NonNls String path = PathMacroMap.quotePath(dir.getAbsolutePath());
String s = macro;
public BasePathMacroManager() {
this(true);
if (StringUtil.endsWithChar(path, '/')) s += "/";
putIfAbsent(result, "file:" + path, "file:" + s, check);
putIfAbsent(result, "file:/" + path, "file:/" + s, check);
putIfAbsent(result, "file://" + path, "file://" + s, check);
putIfAbsent(result, "jar:" + path, "jar:" + s, check);
putIfAbsent(result, "jar:/" + path, "jar:/" + s, check);
putIfAbsent(result, "jar://" + path, "jar://" + s, check);
if (!path.equalsIgnoreCase("e:/") && !path.equalsIgnoreCase("r:/") && !path.equalsIgnoreCase("p:/")) {
putIfAbsent(result, path, s, check);
}
if (dir.getPath().equals(stopAt)) {
break;
}
macro += "/..";
check = true;
dir = dir.getParentFile();
}
}
public ExpandMacroToPathMap getExpandMacroMap() {
ExpandMacroToPathMap result = new ExpandMacroToPathMap();
result.addMacroExpand(PathMacrosImpl.APPLICATION_HOME_MACRO_NAME, PathManager.getHomePath());
if (myUseUserMacroses) {
getPathMacros().addMacroExpands(result);
}
result.addMacroExpand(PathMacrosImpl.USER_HOME_MACRO_NAME, SystemProperties.getUserHome());
getPathMacros().addMacroExpands(result);
return result;
}
@@ -55,10 +85,8 @@ public class BasePathMacroManager extends PathMacroManager {
ReplacePathToMacroMap result = new ReplacePathToMacroMap();
result.addMacroReplacement(PathManager.getHomePath(), PathMacrosImpl.APPLICATION_HOME_MACRO_NAME);
if (myUseUserMacroses) {
getPathMacros().addMacroReplacements(result);
}
result.addMacroReplacement(SystemProperties.getUserHome(), PathMacrosImpl.USER_HOME_MACRO_NAME);
getPathMacros().addMacroReplacements(result);
return result;
}
@@ -19,10 +19,10 @@ import com.intellij.application.options.PathMacrosImpl;
import com.intellij.application.options.ReplacePathToMacroMap;
import com.intellij.openapi.components.ExpandMacroToPathMap;
import com.intellij.openapi.components.PathMacroMap;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.io.File;
@@ -30,7 +30,6 @@ import java.io.File;
public class ProjectPathMacroManager extends BasePathMacroManager {
private final ProjectEx myProject;
public ProjectPathMacroManager(final ProjectEx project) {
myProject = project;
}
@@ -42,47 +41,13 @@ public class ProjectPathMacroManager extends BasePathMacroManager {
}
public ReplacePathToMacroMap getReplacePathMap() {
ReplacePathToMacroMap result = new ReplacePathToMacroMap();
result.putAll(super.getReplacePathMap());
getProjectHomeReplacements(result, true);
ReplacePathToMacroMap result = super.getReplacePathMap();
addFileHierarchyReplacements(result, PathMacrosImpl.PROJECT_DIR_MACRO_NAME, getProjectDir(myProject), null);
return result;
}
private void getProjectHomeReplacements(@NonNls ReplacePathToMacroMap result, final boolean savePathsRelative) {
String projectDir = getProjectDir();
if (projectDir == null) return;
File f = new File(projectDir.replace('/', File.separatorChar));
//LOG.assertTrue(f.exists());
String macro = "$" + PathMacrosImpl.PROJECT_DIR_MACRO_NAME + "$";
boolean check = false;
while (f != null && f.getParentFile() != null) {
String path = PathMacroMap.quotePath(f.getAbsolutePath());
String s = macro;
if (StringUtil.endsWithChar(path, '/')) s += "/";
putIfAbsent(result, "file://" + path, "file://" + s, check);
putIfAbsent(result, "file:/" + path, "file:/" + s, check);
putIfAbsent(result, "file:" + path, "file:" + s, check);
putIfAbsent(result, "jar://" + path, "jar://" + s, check);
putIfAbsent(result, "jar:/" + path, "jar:/" + s, check);
putIfAbsent(result, "jar:" + path, "jar:" + s, check);
//noinspection HardCodedStringLiteral
if (!path.equalsIgnoreCase("e:/") && !path.equalsIgnoreCase("r:/") && !path.equalsIgnoreCase("p:/")) {
putIfAbsent(result, path, s, check);
}
if (!savePathsRelative) break;
check = true;
macro += "/..";
f = f.getParentFile();
}
}
private void getExpandProjectHomeReplacements(ExpandMacroToPathMap result) {
String projectDir = getProjectDir();
String projectDir = getProjectDir(myProject);
if (projectDir == null) return;
File f = new File(projectDir.replace('/', File.separatorChar));
@@ -103,7 +68,7 @@ public class ProjectPathMacroManager extends BasePathMacroManager {
}
@Nullable
private String getProjectDir() {
public static String getProjectDir(Project myProject) {
final VirtualFile baseDir = myProject.getBaseDir();
return baseDir != null ? baseDir.getPath() : null;
}
@@ -268,16 +268,19 @@ public class EditorActionUtil {
private static void moveCaretToStartOfSoftWrappedLine(Editor editor, VisualPosition currentVisual) {
CaretModel caretModel = editor.getCaretModel();
int line = currentVisual.line;
int column = 0;
if (currentVisual.column == 0) {
// We use default column value as '1' below in assumption that we work with soft-wrapped line and don't want to put cursor
// before 'after soft wrap' drawing.
int column = 1;
if (currentVisual.column <= 1) {
line--;
int nonSpaceColumn = findFirstNonSpaceColumnOnTheLine(editor, line);
column = nonSpaceColumn >= 0 ? nonSpaceColumn : 0;
column = nonSpaceColumn >= 1 ? nonSpaceColumn : 1;
}
else {
int nonSpaceColumn = findFirstNonSpaceColumnOnTheLine(editor, currentVisual.line);
if (nonSpaceColumn > 0 /* current visual line is not empty */ && nonSpaceColumn < currentVisual.column) {
if (nonSpaceColumn > 1 /* current visual line is not empty */ && nonSpaceColumn < currentVisual.column) {
column = nonSpaceColumn;
}
}
@@ -364,18 +367,13 @@ public class EditorActionUtil {
// There are soft wrap-introduced visual lines after the target one
return -1;
}
end = findFirstNonSpaceOffsetInRange(document.getCharsSequence(), softWrap.getStart(), logLineEndOffset);
if (end >= 0) {
// Width of soft wrap virtual text that is located at the target visual line.
int result = EditorUtil.calcColumnNumber(editor, softWrapText, j, softWrapTextLength);
result++; // For column reserved for 'after soft wrap' sign.
result += EditorUtil.calcColumnNumber(editor, document.getCharsSequence(), softWrap.getStart(), end);
return result;
}
else {
return -1;
}
}
int end = findFirstNonSpaceOffsetInRange(document.getCharsSequence(), softWrap.getStart(), logLineEndOffset);
if (end >= 0) {
return EditorUtil.calcColumnNumber(editor, document.getCharsSequence(), softWrap.getStart(), end);
}
else {
return -1;
}
}
return -1;
@@ -415,6 +413,7 @@ public class EditorActionUtil {
LogicalPosition blockSelectionStart = selectionModel.hasBlockSelection()
? selectionModel.getBlockStart()
: caretModel.getLogicalPosition();
SoftWrapModel softWrapModel = editor.getSoftWrapModel();
int lineNumber = editor.getCaretModel().getLogicalPosition().line;
if (lineNumber >= document.getLineCount()) {
@@ -434,7 +433,7 @@ public class EditorActionUtil {
LogicalPosition logical = editor.visualToLogicalPosition(visualEndOfLineWithCaret);
int offset = editor.logicalPositionToOffset(logical);
if (offset < editor.getDocument().getTextLength()) {
SoftWrapModel softWrapModel = editor.getSoftWrapModel();
TextChange softWrap = softWrapModel.getSoftWrap(offset);
if (softWrap == null) {
// Same offset may correspond to positions on different visual lines in case of soft wraps presence
@@ -442,21 +441,33 @@ public class EditorActionUtil {
// Hence, we check for soft wraps presence at two offsets.
softWrap = softWrapModel.getSoftWrap(offset + 1);
}
int line = currentVisualCaret.line;
int column = currentVisualCaret.column;
if (softWrap != null) {
int line = currentVisualCaret.line + 1;
int column = EditorUtil.getLastVisualLineColumnNumber(editor, line);
visualEndOfLineWithCaret = new VisualPosition(line, column);
line++;
column = EditorUtil.getLastVisualLineColumnNumber(editor, line);
}
// There is a possible case that the last visual line of particular logical line contains only white spaces. We want to move
// caret just after 'after soft wrap' drawing then.
else if (line == editor.offsetToVisualPosition(document.getLineEndOffset(lineNumber)).line) {
column = 1;
}
visualEndOfLineWithCaret = new VisualPosition(line, column);
}
}
int offset;
int newOffset;
LogicalPosition logLineEnd = editor.visualToLogicalPosition(visualEndOfLineWithCaret);
int offset = editor.logicalPositionToOffset(logLineEnd);
offset = editor.logicalPositionToOffset(logLineEnd);
lineNumber = logLineEnd.line;
int newOffset = offset;
newOffset = offset;
CharSequence text = document.getCharsSequence();
for (int i = newOffset - 1; i >= document.getLineStartOffset(lineNumber); i--) {
if (softWrapModel.getSoftWrap(i) != null) {
break;
}
if (text.charAt(i) != ' ' && text.charAt(i) != '\t') {
break;
}
@@ -22,7 +22,6 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry;
import com.intellij.openapi.editor.impl.FontInfo;
import com.intellij.openapi.editor.impl.IterationState;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
@@ -158,17 +157,42 @@ public class EditorUtil {
}
public static int calcOffset(Editor editor, CharSequence text, int start, int end, int columnNumber, int tabSize) {
// If all tabs here goes before any other chars in the line we may use an optimization here.
boolean useOptimization = true;
final int maxScanIndex = Math.min(start + columnNumber + 1, end);
if (editor == null) {
return calcSoftWrapUnawareOffset(text, start, maxScanIndex, columnNumber, tabSize);
}
int column = 0;
int tabAnchor = 0;
SoftWrapModel softWrapModel = editor.getSoftWrapModel();
for (int i = start; i < maxScanIndex; i++) {
TextChange softWrap = softWrapModel.getSoftWrap(i);
if (softWrap != null) {
tabAnchor = softWrapModel.getSoftWrapIndentWidthInColumns(softWrap);
}
if (column >= columnNumber) {
return i;
}
int diff = textWidthInColumns(editor, text, i, i + 1, tabAnchor);
if (column + diff > columnNumber) {
// We want to return offset that points to the tabulation symbol if it's represented in multiple columns and target visual
// column points inside it.
return i;
}
column += diff;
tabAnchor += diff;
}
return end;
}
private static int calcSoftWrapUnawareOffset(CharSequence text, int start, int end, int columnNumber, int tabSize) {
boolean hasNonTabs = false;
boolean hasTabs = false;
final int maxScanIndex = Math.min(start + columnNumber + 1, end);
for (int i = start; i < maxScanIndex; i++) {
for (int i = start; i < end; i++) {
if (text.charAt(i) == '\t') {
hasTabs = true;
if (hasNonTabs) {
useOptimization = false;
break;
}
} else {
@@ -176,52 +200,18 @@ public class EditorUtil {
}
}
if (editor == null || useOptimization) {
if (!hasTabs) return Math.min(start + columnNumber, end);
if (!hasTabs) return Math.min(start + columnNumber, end);
int shift = 0;
int offset = start;
for (; offset < end && offset + shift < start + columnNumber; offset++) {
if (text.charAt(offset) == '\t') {
shift += getTabLength(offset + shift - start, tabSize) - 1;
}
}
if (offset + shift > start + columnNumber) {
offset--;
}
return offset;
}
EditorEx editorImpl = (EditorEx)editor;
int shift = 0;
int offset = start;
IterationState state = new IterationState(editorImpl, offset, false);
int fontType = state.getMergedAttributes().getFontType();
int column = 0;
int x = 0;
int spaceSize = getSpaceWidth(fontType, editorImpl);
while (column < columnNumber) {
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
char c = offset < end ? text.charAt(offset++) : ' ';
if (c == '\t') {
int prevX = x;
x = nextTabStop(x, editorImpl);
column += (x - prevX) / spaceSize;
}
else {
x += charWidth(c, fontType, editorImpl);
column++;
for (; offset < end && offset + shift < start + columnNumber; offset++) {
if (text.charAt(offset) == '\t') {
shift += getTabLength(offset + shift - start, tabSize) - 1;
}
}
if (column == columnNumber && offset < end && text.charAt(offset) == '\t' && (nextTabStop(x, editorImpl) - x) / spaceSize == 0) {
offset++;
if (offset + shift > start + columnNumber) {
offset--;
}
if (column > columnNumber) offset--;
return offset;
}
@@ -239,15 +229,21 @@ public class EditorUtil {
public static int calcColumnNumber(Editor editor, CharSequence text, int start, int offset, int tabSize) {
boolean useOptimization = true;
if (editor != null) {
TextChange softWrap = editor.getSoftWrapModel().getSoftWrap(start);
useOptimization = softWrap == null;
}
boolean hasNonTabs = false;
for (int i = start; i < offset; i++) {
if (text.charAt(i) == '\t') {
if (hasNonTabs) {
useOptimization = false;
break;
if (useOptimization) {
for (int i = start; i < offset; i++) {
if (text.charAt(i) == '\t') {
if (hasNonTabs) {
useOptimization = false;
break;
}
} else {
hasNonTabs = true;
}
} else {
hasNonTabs = true;
}
}
@@ -315,9 +311,6 @@ public class EditorUtil {
* @return number of visual columns required to represent tabulation symbols that starts at the given column
*/
public static int tabWidthInColumns(@NotNull Editor editor, int visualColumn) {
if (!editor.getSettings().isWhitespacesShown()) {
return 1;
}
int tabSize = getTabSize(editor);
int tabsNumber = visualColumn / tabSize;
return (tabsNumber + 1) * tabSize - visualColumn;
@@ -365,12 +358,7 @@ public class EditorUtil {
continue;
}
if (editor.getSettings().isWhitespacesShown()) {
result += nextTabStop(x + result, editor) - result - x;
}
else {
result += getSpaceWidth(fontType, editor);
}
result += nextTabStop(x + result, editor) - result - x;
}
return result;
}
@@ -179,34 +179,43 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener {
if (newColumnNumber < 0) newColumnNumber = 0;
if (newLineNumber < 0) newLineNumber = 0;
VisualPosition pos = new VisualPosition(newLineNumber, newColumnNumber);
int lastColumnNumber = newColumnNumber;
if (!editorSettings.isCaretInsideTabs()) {
if (!editorSettings.isCaretInsideTabs() && !myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) {
LogicalPosition log = myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber));
int offset = myEditor.logicalPositionToOffset(log);
CharSequence text = myEditor.getDocument().getCharsSequence();
if (offset >= 0 && offset < myEditor.getDocument().getTextLength()) {
if (text.charAt(offset) == '\t') {
if (text.charAt(offset) == '\t' && (columnShift <= 0 || offset == myOffset)) {
if (columnShift <= 0) {
newColumnNumber = myEditor.offsetToVisualPosition(offset).column;
}
else {
if (myEditor.offsetToVisualPosition(offset).column < newColumnNumber) {
TextChange softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset + 1);
// There is a possible case that tabulation symbol is the last document symbol represented on a visual line before
// soft wrap. We can't just use column from 'offset + 1' because it would point on a next visual line.
if (softWrap == null) {
newColumnNumber = myEditor.offsetToVisualPosition(offset + 1).column;
}
else {
newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber);
}
}
}
}
}
VisualPosition pos = new VisualPosition(newLineNumber, newColumnNumber);
pos = new VisualPosition(newLineNumber, newColumnNumber);
if (columnShift != 0 && lineShift == 0 && myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) {
LogicalPosition logical = myEditor.visualToLogicalPosition(pos);
int offsetToUse = myEditor.logicalPositionToOffset(logical);
if (columnShift < 0) {
offsetToUse--;
int softWrapOffset = myEditor.logicalPositionToOffset(logical);
if (columnShift >= 0) {
moveToOffset(softWrapOffset);
}
else {
int line = myEditor.offsetToVisualPosition(softWrapOffset - 1).line;
moveToVisualPosition(new VisualPosition(line, EditorUtil.getLastVisualLineColumnNumber(myEditor, line)));
}
moveToOffset(offsetToUse);
}
else {
moveToVisualPosition(pos);
@@ -839,8 +839,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
int x = 0;
int charWidth;
outer:
while (true) {
charWidth = -1;
if (offset >= textLength) {
break;
}
@@ -879,12 +881,12 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
continue;
}
prevX = x;
int diff = charToVisibleWidth(c, fontType, x);
if (diff == 0) {
charWidth = charToVisibleWidth(c, fontType, x);
if (charWidth == 0) {
break outer;
}
x += diff;
x += charWidth;
if (x >= px) {
break outer;
}
@@ -894,7 +896,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
// Process 'after soft wrap' sign.
prevX = x;
x += mySoftWrapModel.getMinDrawingWidth(SoftWrapDrawingType.AFTER_SOFT_WRAP);
charWidth = mySoftWrapModel.getMinDrawingWidth(SoftWrapDrawingType.AFTER_SOFT_WRAP);
x += charWidth;
if (x >= px) {
break outer;
}
@@ -903,11 +906,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
prevX = x;
c = text.charAt(offset);
int diff = charToVisibleWidth(c, fontType, x);
if (diff == 0) {
charWidth = charToVisibleWidth(c, fontType, x);
if (charWidth == 0) {
break;
} else {
x += diff;
x += charWidth;
}
if (x >= px) {
@@ -919,17 +922,17 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
int charWidth = EditorUtil.charWidth(c, fontType, this);
if (charWidth < 0) {
charWidth = EditorUtil.charWidth(c, fontType, this);
}
if (x >= px && c == '\t') {
if (mySettings.isCaretInsideTabs()) {
column += (px - prevX) / spaceSize;
if ((px - prevX) % spaceSize > spaceSize / 2) column++;
}
else {
if ((x - px) * 2 < x - prevX) {
column += (x - prevX) / spaceSize;
}
else if ((x - px) * 2 < x - prevX) {
column += columnsNumber(c, x, prevX, spaceSize);
}
}
else {
@@ -977,7 +980,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
if (c != '\t') {
return 1;
}
return (x - prevX) / spaceSize;
int result = (x - prevX) / spaceSize;
if ((x - prevX) % spaceSize > 0) {
result++;
}
return result;
}
@NotNull
@@ -1080,12 +1087,12 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
int x = getTabbedTextWidth(lineStartOffset, column);
return new Point(x + reserved, y);
int x = getTabbedTextWidth(lineStartOffset, column, reserved);
return new Point(x, y);
}
private int getTabbedTextWidth(int startOffset, int length) {
int x = 0;
private int getTabbedTextWidth(int startOffset, int length, int xOffset) {
int x = xOffset;
if (startOffset == 0 && myPrefixText != null) {
for (char c : myPrefixText) {
x += EditorUtil.charWidth(c, myPrefixAttributes.getFontType(), this);
@@ -1128,7 +1135,14 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
if (c == '\t') {
int prevX = x;
x = EditorUtil.nextTabStop(x, this);
column += (x - prevX) / spaceSize;
int columnDiff = (x - prevX) / spaceSize;
if ((x - prevX) % spaceSize > 0) {
// There is a possible case that tabulation symbol takes more than one visual column to represent and it's shown at
// soft-wrapped line. Soft wrap sign width may be not divisible by space size, hence, part of tabulation symbol represented
// as a separate visual column may take less space than space width.
columnDiff++;
}
column += columnDiff;
}
else {
x += EditorUtil.charWidth(c, fontType, this);
@@ -4843,11 +4857,17 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
fontType = state.getMergedAttributes().getFontType();
}
TextChange softWrap = getSoftWrapModel().getSoftWrap(i);
if (softWrap != null) {
column++; // For 'after soft wrap' drawing.
x = getSoftWrapModel().getMinDrawingWidth(SoftWrapDrawingType.AFTER_SOFT_WRAP);
}
char c = text.charAt(i);
if (c == '\t') {
int prevX = x;
x = EditorUtil.nextTabStop(x, this);
column += (x - prevX) / spaceSize;
column += columnsNumber(c, x, prevX, spaceSize);
//column += Math.max(1, (x - prevX) / spaceSize);
}
else {
@@ -277,7 +277,6 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi
mySelectionMarker.release();
mySelectionMarker = null;
fireSelectionChanged(startOffset, endOffset, myLastSelectionStart, myLastSelectionStart);
updateSystemSelection();
}
}
@@ -253,12 +253,23 @@ public class SoftWrapModelImpl implements SoftWrapModelEx {
// We consider visual positions that point after the last symbol before soft wrap and the first symbol after soft wrap to not
// belong to soft wrap-introduced virtual space.
VisualPosition visualAfterSoftWrap = myEditor.offsetToVisualPosition(offset);
if (visualAfterSoftWrap.equals(visual)) {
if (visualAfterSoftWrap.line == visual.line && visualAfterSoftWrap.column <= visual.column) {
return false;
}
VisualPosition visualBeforeSoftWrap = myEditor.offsetToVisualPosition(offset - 1);
return visual.line > visualBeforeSoftWrap.line || visual.column > visualBeforeSoftWrap.column + 1;
int columnOffset = 0;
LogicalPosition logLineStart = myEditor.visualToLogicalPosition(new VisualPosition(visualBeforeSoftWrap.line, 0));
if (logLineStart.softWrapLinesOnCurrentLogicalLine > 0) {
int offsetLineStart = myEditor.logicalPositionToOffset(logLineStart);
softWrap = getSoftWrap(offsetLineStart);
if (softWrap != null) {
columnOffset = getSoftWrapIndentWidthInColumns(softWrap);
}
}
int width = EditorUtil.textWidthInColumns(myEditor, myEditor.getDocument().getCharsSequence(), offset - 1, offset, columnOffset);
int softWrapStartColumn = visualBeforeSoftWrap.column + width;
return visual.line > visualBeforeSoftWrap.line || visual.column > softWrapStartColumn;
}
@Override
@@ -269,7 +269,17 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
// Try to find target offset that is not greater than preferred position.
for (int i = preferred; i > min; i--) {
char c = text[i];
if ((i < preferred) && (SPECIAL_SYMBOLS_TO_WRAP_AFTER.contains(c) || WHITE_SPACES.contains(c))) {
if (i < preferred && WHITE_SPACES.contains(c)) {
return i + 1;
}
// Don't wrap on the non-id symbol preceded by another non-id symbol. E.g. consider that we have a statement
// like 'foo(int... args)'. We don't want to wrap on the second or third dots then.
if (i > min + 1 && !isIdSymbol(c) && !isIdSymbol(text[i - 1])) {
continue;
}
if ((i < preferred) && SPECIAL_SYMBOLS_TO_WRAP_AFTER.contains(c)) {
return i + 1;
}
if (SPECIAL_SYMBOLS_TO_WRAP_BEFORE.contains(c) || WHITE_SPACES.contains(c)) {
@@ -286,7 +296,15 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
// Try to find target offset that is greater than preferred position.
for (int i = preferred + 1; i < max; i++) {
char c = text[i];
if (SPECIAL_SYMBOLS_TO_WRAP_BEFORE.contains(c) || WHITE_SPACES.contains(c)) {
if (WHITE_SPACES.contains(c)) {
return i;
}
// Don't wrap on the non-id symbol preceded by another non-id symbol. E.g. consider that we have a statement
// like 'foo(int... args)'. We don't want to wrap on the second or third dots then.
if (i < max - 1 && !isIdSymbol(c) && !isIdSymbol(text[i + 1]) && !isIdSymbol(text[i - 1])) {
continue;
}
if (SPECIAL_SYMBOLS_TO_WRAP_BEFORE.contains(c)) {
return i;
}
if (SPECIAL_SYMBOLS_TO_WRAP_AFTER.contains(c) && i < max - 1) {
@@ -114,7 +114,9 @@ public class SoftWrapDataMapper {
return result;
}
}
context.onSoftWrapSymbol('a'); // Emulate 'after soft wrap' sign
// Emulate 'after soft wrap' sign
//int afterSoftWrapColumns = myEditor.getSoftWrapModel().get
context.onSoftWrapSymbol('a');
}
// Process document symbol.
@@ -266,9 +266,11 @@ public class JarHandler implements FileSystemInterface {
}
final ZipFile zip = getZip();
assert zip != null;
assert zip != null : file;
final InputStream stream = zip.getInputStream(entry);
assert stream != null : file;
try {
return FileUtil.loadBytes(stream, (int)entry.getSize());
}

Some files were not shown because too many files have changed in this diff Show More