From b9261670a8e5551c1ec4caa4b1eb1f3d41f5ef95 Mon Sep 17 00:00:00 2001 From: Nikolay Mikhaylov Date: Thu, 22 Oct 2015 12:42:09 +0300 Subject: [PATCH 01/17] Fix EA-74670 - NPE: MavenManager.getOrLoadMavenArtifactJars --- .../library/RepositoryAttachHandler.java | 22 +++++++++++-------- .../MavenDependenciesRemoteManager.java | 6 ++++- .../library/remote/MavenRemoteManager.java | 2 ++ .../utils/library/remote/MavenRemoteTask.java | 1 + .../remote/MavenVersionsRemoteManager.java | 3 +++ 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/RepositoryAttachHandler.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/RepositoryAttachHandler.java index 1ff9174427e5..633cce333cd3 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/RepositoryAttachHandler.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/RepositoryAttachHandler.java @@ -94,13 +94,15 @@ public class RepositoryAttachHandler { boolean attachJavaDoc = dialog.getAttachJavaDoc(); boolean attachSources = dialog.getAttachSources(); List repositories = dialog.getRepositories(); - NewLibraryConfiguration configuration = resolveAndDownload(project, coord, attachJavaDoc, attachSources, copyTo, repositories); + @Nullable NewLibraryConfiguration configuration = + resolveAndDownload(project, coord, attachJavaDoc, attachSources, copyTo, repositories); if (configuration == null) { Messages.showErrorDialog(parentComponent, ProjectBundle.message("maven.downloading.failed", coord), CommonBundle.getErrorTitle()); } return configuration; } + @Nullable public static NewLibraryConfiguration resolveAndDownload(final Project project, final String coord, boolean attachJavaDoc, @@ -108,7 +110,7 @@ public class RepositoryAttachHandler { @Nullable final String copyTo, List repositories) { RepositoryLibraryProperties libraryProperties = new RepositoryLibraryProperties(coord); - final List roots = MavenDependenciesRemoteManager.getInstance(project) + final @Nullable List roots = MavenDependenciesRemoteManager.getInstance(project) .downloadDependenciesModal(libraryProperties, attachSources, attachJavaDoc, copyTo); if (roots == null || roots.size() == 0) { return null; @@ -126,13 +128,15 @@ public class RepositoryAttachHandler { }; } - public static List resolveAndDownloadImpl(final Project project, - final String coord, - boolean attachJavaDoc, - boolean attachSources, - @Nullable final String copyTo, - List repositories, - ProgressIndicator indicator) { + public static + @NotNull + List resolveAndDownloadImpl(final Project project, + final String coord, + boolean attachJavaDoc, + boolean attachSources, + @Nullable final String copyTo, + List repositories, + ProgressIndicator indicator) { final SmartList extraTypes = new SmartList(); if (attachSources) extraTypes.add(MavenExtraArtifactType.SOURCES); if (attachJavaDoc) extraTypes.add(MavenExtraArtifactType.DOCS); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenDependenciesRemoteManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenDependenciesRemoteManager.java index 3803c3c11211..12196f733564 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenDependenciesRemoteManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenDependenciesRemoteManager.java @@ -49,7 +49,9 @@ public class MavenDependenciesRemoteManager schedule(this, new Argument(libraryProperties, downloadSources, downloadJavaDocs, copyTo), resultProcessor, false); } - public List downloadDependencies( + public + @Nullable + List downloadDependencies( RepositoryLibraryProperties libraryProperties, boolean downloadSources, boolean downloadJavaDocs, @@ -57,6 +59,7 @@ public class MavenDependenciesRemoteManager return getSynchronously(this, new Argument(libraryProperties, downloadSources, downloadJavaDocs, copyTo)); } + @Nullable public List downloadDependenciesModal( final RepositoryLibraryProperties libraryProperties, final boolean downloadSources, @@ -68,6 +71,7 @@ public class MavenDependenciesRemoteManager } @Override + @NotNull public List execute(@NotNull Argument arg, ProgressIndicator indicator) { String coordinates = arg.libraryProperties.getGroupId() + ":" + arg.libraryProperties.getArtifactId() + ":" + diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteManager.java index a526984bf335..29e7db350bcf 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteManager.java @@ -77,6 +77,7 @@ public abstract class MavenRemoteManager result = Ref.create(); new Task.Modal(myProject, title, false) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteTask.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteTask.java index 965910efd53b..0585cf3caf74 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteTask.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteTask.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface MavenRemoteTask { + @NotNull Result execute(@NotNull Argument arg, ProgressIndicator indicator); String getName(@NotNull Argument arg); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenVersionsRemoteManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenVersionsRemoteManager.java index 8a96c4743551..d845b18b337c 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenVersionsRemoteManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenVersionsRemoteManager.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.maven.utils.library.remote; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.dom.MavenVersionComparable; import org.jetbrains.idea.maven.model.MavenRemoteRepository; import org.jetbrains.idea.maven.model.MavenRepositoryInfo; @@ -49,10 +50,12 @@ public class MavenVersionsRemoteManager schedule(this, RepositoryLibraryDescription.findDescription(groupId, artifactId), resultProcessor, false); } + @Nullable public List getMavenArtifactVersions(String groupId, String artifactId) { return getSynchronously(this, RepositoryLibraryDescription.findDescription(groupId, artifactId)); } + @NotNull @Override public List execute(@NotNull RepositoryLibraryDescription repositoryLibraryDescription, ProgressIndicator indicator) { MavenEmbeddersManager manager = MavenProjectsManager.getInstance(myProject).getEmbeddersManager(); From ca520ef2aaf39201a816141fccb63d87bc3c012c Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Thu, 22 Oct 2015 13:04:37 +0300 Subject: [PATCH 02/17] IDEA-146602 Gradle: endless dependencies --- .../BaseGradleProjectResolverExtension.java | 266 ++++++++++-------- .../project/GradleProjectResolver.java | 1 + .../model/ExternalMultiLibraryDependency.java | 52 ++++ ...DefaultExternalMultiLibraryDependency.java | 82 ++++++ .../util/DependencyResolverImpl.groovy | 53 +++- 5 files changed, 324 insertions(+), 130 deletions(-) create mode 100644 plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ExternalMultiLibraryDependency.java create mode 100644 plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/model/DefaultExternalMultiLibraryDependency.java diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java index 1afd0445e172..42148d32f84e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java @@ -60,6 +60,7 @@ import org.gradle.tooling.model.idea.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.DefaultExternalDependencyId; import org.jetbrains.plugins.gradle.ExternalDependencyId; import org.jetbrains.plugins.gradle.model.*; import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData; @@ -403,11 +404,48 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver processSourceSets(externalProject, ideModule, new SourceSetsProcessor() { @Override public void process(@NotNull DataNode dataNode, @NotNull ExternalSourceSet sourceSet) { - Map dependencyMap = ContainerUtil.newLinkedHashMap(); - for (ExternalDependency dependency : sourceSet.getDependencies()) { - ExternalDependency d = dependencyMap.get(dependency.getId()); - if (d != null) { - DependencyScope prevScope = d.getScope() == null ? DependencyScope.COMPILE : DependencyScope.valueOf(d.getScope()); + Map dependencyMap = ContainerUtil.newHashMap(); + + Queue queue = ContainerUtil.newLinkedList(sourceSet.getDependencies()); + while (!queue.isEmpty()) { + final ExternalDependency dependency = queue.remove(); + ExternalDependency seenDependency = dependencyMap.get(dependency.getId()); + if (seenDependency != null) { + if (dependency instanceof ExternalLibraryDependency) { + if (seenDependency instanceof ExternalLibraryDependency && + !FileUtil.filesEqual(((ExternalLibraryDependency)seenDependency).getFile(), + ((ExternalLibraryDependency)dependency).getFile())) { + DefaultExternalMultiLibraryDependency mergedDependency = new DefaultExternalMultiLibraryDependency(); + mergedDependency.setName(dependency.getId().getName()); + mergedDependency.setGroup(dependency.getId().getGroup()); + mergedDependency.setVersion(dependency.getId().getVersion()); + mergedDependency.setPackaging(dependency.getId().getPackaging()); + mergedDependency.setClassifier(dependency.getId().getClassifier()); + mergedDependency.setScope(dependency.getScope()); + mergedDependency.setClasspathOrder(dependency.getClasspathOrder()); + mergedDependency.getDependencies().addAll(dependency.getDependencies()); + + mergedDependency.getFiles().addAll(ContainerUtil.packNullables( + ((ExternalLibraryDependency)seenDependency).getFile(), ((ExternalLibraryDependency)dependency).getFile())); + mergedDependency.getSources().addAll((ContainerUtil.packNullables( + ((ExternalLibraryDependency)seenDependency).getSource(), ((ExternalLibraryDependency)dependency).getSource()))); + mergedDependency.getJavadoc().addAll((ContainerUtil.packNullables( + ((ExternalLibraryDependency)seenDependency).getJavadoc(), ((ExternalLibraryDependency)dependency).getJavadoc()))); + + dependencyMap.put(dependency.getId(), mergedDependency); + continue; + } + else if (seenDependency instanceof DefaultExternalMultiLibraryDependency) { + DefaultExternalMultiLibraryDependency mergedDependency = (DefaultExternalMultiLibraryDependency)seenDependency; + mergedDependency.getFiles().addAll(ContainerUtil.packNullables(((ExternalLibraryDependency)dependency).getFile())); + mergedDependency.getSources().addAll(ContainerUtil.packNullables(((ExternalLibraryDependency)dependency).getSource())); + mergedDependency.getJavadoc().addAll(ContainerUtil.packNullables(((ExternalLibraryDependency)dependency).getJavadoc())); + continue; + } + } + + DependencyScope prevScope = + seenDependency.getScope() == null ? DependencyScope.COMPILE : DependencyScope.valueOf(seenDependency.getScope()); DependencyScope currentScope = dependency.getScope() == null ? DependencyScope.COMPILE : DependencyScope.valueOf(dependency.getScope()); @@ -415,12 +453,11 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver if (prevScope.isForProductionRuntime() && currentScope.isForProductionRuntime()) continue; } - dependencyMap.put(dependency.getId(), dependency); + dependencyMap.put(new DefaultExternalDependencyId(dependency.getId()), dependency); + queue.addAll(dependency.getDependencies()); } - for (ExternalDependency dependency : dependencyMap.values()) { - buildSourceSetDependency(sourceSetMap, dataNode, dependency, ideProject); - } + buildSourceSetDependency(sourceSetMap, dependencyMap, dataNode, sourceSet.getDependencies(), ideProject); } }); @@ -928,125 +965,120 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver } private static void buildSourceSetDependency(@NotNull Map, ExternalSourceSet>> sourceSetMap, - @NotNull DataNode ownerModule, - @NotNull ExternalDependency dependency, - @NotNull DataNode ideProject) - throws IllegalStateException { + @NotNull Map mergedDependencyMap, + @NotNull DataNode ownerDataNode, + @NotNull Collection dependencies, + @NotNull DataNode ideProject) throws IllegalStateException { - DependencyScope dependencyScope = getDependencyScope(dependency.getScope()); - - if (dependency instanceof ExternalProjectDependency) { - String moduleId = getModuleId((ExternalProjectDependency)dependency); - Pair, ExternalSourceSet> projectPair = sourceSetMap.get(moduleId); - ModuleDependencyData moduleDependencyData = new ModuleDependencyData(ownerModule.getData(), projectPair.first.getData()); - moduleDependencyData.setScope(dependencyScope); - if ("test".equals(projectPair.second.getName())) { - moduleDependencyData.setProductionOnTestDependency(true); - } - moduleDependencyData.setOrder(dependency.getClasspathOrder()); - moduleDependencyData.setExported(dependency.getExported()); - DataNode ideModuleDependencyNode = ownerModule.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData); - for (ExternalDependency externalDependency : dependency.getDependencies()) { - buildTransitiveDependency(sourceSetMap, ideModuleDependencyNode, externalDependency, ideProject); - } + Map dependencyMap = ContainerUtil.newLinkedHashMap(); + for (ExternalDependency dependency : dependencies) { + dependencyMap.put(dependency.getId(), dependency); } - if (dependency instanceof ExternalLibraryDependency) { - final LibraryLevel level = LibraryLevel.PROJECT; - String libraryName = dependency.getId().getPresentableName(); - final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); - LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule.getData(), library, level); - libraryDependencyData.setScope(dependencyScope); - libraryDependencyData.setOrder(dependency.getClasspathOrder()); - libraryDependencyData.setExported(dependency.getExported()); - library.addPath(LibraryPathType.BINARY, ((ExternalLibraryDependency)dependency).getFile().getAbsolutePath()); - File sourcePath = ((ExternalLibraryDependency)dependency).getSource(); + for (ExternalDependency dependency : dependencyMap.values()) { + final ExternalDependency mergedDependency = ContainerUtil.getOrElse(mergedDependencyMap, dependency.getId(), dependency); + DependencyScope dependencyScope = getDependencyScope(mergedDependency.getScope()); - if (sourcePath != null) { - library.addPath(LibraryPathType.SOURCE, sourcePath.getAbsolutePath()); + ModuleData ownerModule = null; + if (ownerDataNode.getData() instanceof ModuleData) { + ownerModule = (ModuleData)ownerDataNode.getData(); } - DataNode libraryDependencyDataNode = - ownerModule.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); - - linkProjectLibrary(ideProject, library); - - for (ExternalDependency externalDependency : dependency.getDependencies()) { - buildTransitiveDependency(sourceSetMap, libraryDependencyDataNode, externalDependency, ideProject); - } - } - if (dependency instanceof FileCollectionDependency) { - final LibraryLevel level = LibraryLevel.MODULE; - String libraryName = ""; - final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); - LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule.getData(), library, level); - libraryDependencyData.setScope(dependencyScope); - libraryDependencyData.setOrder(dependency.getClasspathOrder()); - libraryDependencyData.setExported(dependency.getExported()); - - for (File file : ((FileCollectionDependency)dependency).getFiles()) { - library.addPath(LibraryPathType.BINARY, file.getAbsolutePath()); + else if (ownerDataNode.getData() instanceof DependencyData) { + ownerModule = ((DependencyData)ownerDataNode.getData()).getOwnerModule(); } - ownerModule.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); - } - if (dependency instanceof UnresolvedExternalDependency) { - final LibraryLevel level = LibraryLevel.PROJECT; - String libraryName = dependency.getId().getPresentableName(); - final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName, true); - LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule.getData(), library, level); - libraryDependencyData.setScope(dependencyScope); - final String failureMessage = ((UnresolvedExternalDependency)dependency).getFailureMessage(); - if (failureMessage != null) { - library.addPath(LibraryPathType.BINARY, failureMessage); - } - ownerModule.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); - linkProjectLibrary(ideProject, library); - } - } + assert ownerModule != null; - private static void buildTransitiveDependency(@NotNull Map, ExternalSourceSet>> sourceSetMap, - @NotNull DataNode ownerModule, - @NotNull ExternalDependency dependency, - @NotNull DataNode ideProject) - throws IllegalStateException { - - DependencyScope dependencyScope = getDependencyScope(dependency.getScope()); - if (dependency instanceof ExternalProjectDependency) { - String moduleId = getModuleId((ExternalProjectDependency)dependency); - Pair, ExternalSourceSet> projectPair = sourceSetMap.get(moduleId); - ModuleDependencyData moduleDependencyData = - new ModuleDependencyData(ownerModule.getData().getOwnerModule(), projectPair.first.getData()); - moduleDependencyData.setScope(dependencyScope); - if ("test".equals(projectPair.second.getName())) { - moduleDependencyData.setProductionOnTestDependency(true); + if (mergedDependency instanceof ExternalProjectDependency) { + String moduleId = getModuleId((ExternalProjectDependency)mergedDependency); + Pair, ExternalSourceSet> projectPair = sourceSetMap.get(moduleId); + ModuleDependencyData moduleDependencyData = new ModuleDependencyData(ownerModule, projectPair.first.getData()); + moduleDependencyData.setScope(dependencyScope); + if ("test".equals(projectPair.second.getName())) { + moduleDependencyData.setProductionOnTestDependency(true); + } + moduleDependencyData.setOrder(mergedDependency.getClasspathOrder()); + moduleDependencyData.setExported(mergedDependency.getExported()); + DataNode ideModuleDependencyNode = + ownerDataNode.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData); + buildSourceSetDependency(sourceSetMap, mergedDependencyMap, ideModuleDependencyNode, dependency.getDependencies(), ideProject); } - moduleDependencyData.setOrder(dependency.getClasspathOrder()); - moduleDependencyData.setExported(dependency.getExported()); - DataNode ideModuleDependencyNode = ownerModule.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData); - for (ExternalDependency externalDependency : dependency.getDependencies()) { - buildTransitiveDependency(sourceSetMap, ideModuleDependencyNode, externalDependency, ideProject); - } - } - if (dependency instanceof ExternalLibraryDependency) { - final LibraryLevel level = LibraryLevel.PROJECT; - String libraryName = dependency.getId().getPresentableName(); - final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); - LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule.getData().getOwnerModule(), library, level); + if (mergedDependency instanceof ExternalLibraryDependency) { + final LibraryLevel level = LibraryLevel.PROJECT; + String libraryName = mergedDependency.getId().getPresentableName(); + final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); + LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); + libraryDependencyData.setScope(dependencyScope); + libraryDependencyData.setOrder(mergedDependency.getClasspathOrder()); + libraryDependencyData.setExported(mergedDependency.getExported()); - libraryDependencyData.setScope(dependencyScope); - libraryDependencyData.setOrder(dependency.getClasspathOrder()); - libraryDependencyData.setExported(dependency.getExported()); - library.addPath(LibraryPathType.BINARY, ((ExternalLibraryDependency)dependency).getFile().getAbsolutePath()); - File sourcePath = ((ExternalLibraryDependency)dependency).getSource(); - if (sourcePath != null) { - library.addPath(LibraryPathType.SOURCE, sourcePath.getAbsolutePath()); - } - DataNode libraryDependencyDataNode = - ownerModule.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); + library.addPath(LibraryPathType.BINARY, ((ExternalLibraryDependency)mergedDependency).getFile().getAbsolutePath()); + File sourcePath = ((ExternalLibraryDependency)mergedDependency).getSource(); + if (sourcePath != null) { + library.addPath(LibraryPathType.SOURCE, sourcePath.getAbsolutePath()); + } + File javaDocPath = ((ExternalLibraryDependency)mergedDependency).getJavadoc(); + if (javaDocPath != null) { + library.addPath(LibraryPathType.DOC, javaDocPath.getAbsolutePath()); + } + DataNode libraryDependencyDataNode = + ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); - linkProjectLibrary(ideProject, library); - for (ExternalDependency externalDependency : dependency.getDependencies()) { - buildTransitiveDependency(sourceSetMap, libraryDependencyDataNode, externalDependency, ideProject); + linkProjectLibrary(ideProject, library); + + buildSourceSetDependency(sourceSetMap, mergedDependencyMap, libraryDependencyDataNode, dependency.getDependencies(), ideProject); + } + if (mergedDependency instanceof ExternalMultiLibraryDependency) { + final LibraryLevel level = LibraryLevel.MODULE; + String libraryName = mergedDependency.getId().getPresentableName(); + final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); + LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); + libraryDependencyData.setScope(dependencyScope); + libraryDependencyData.setOrder(mergedDependency.getClasspathOrder()); + libraryDependencyData.setExported(mergedDependency.getExported()); + + for (File file : ((ExternalMultiLibraryDependency)mergedDependency).getFiles()) { + library.addPath(LibraryPathType.BINARY, file.getAbsolutePath()); + } + for (File file : ((ExternalMultiLibraryDependency)mergedDependency).getSources()) { + library.addPath(LibraryPathType.SOURCE, file.getAbsolutePath()); + } + for (File file : ((ExternalMultiLibraryDependency)mergedDependency).getJavadoc()) { + library.addPath(LibraryPathType.DOC, file.getAbsolutePath()); + } + + DataNode libraryDependencyDataNode = + ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); + + buildSourceSetDependency(sourceSetMap, mergedDependencyMap, libraryDependencyDataNode, dependency.getDependencies(), ideProject); + } + if (mergedDependency instanceof FileCollectionDependency) { + final LibraryLevel level = LibraryLevel.MODULE; + String libraryName = ""; + final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); + LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); + libraryDependencyData.setScope(dependencyScope); + libraryDependencyData.setOrder(mergedDependency.getClasspathOrder()); + libraryDependencyData.setExported(mergedDependency.getExported()); + + for (File file : ((FileCollectionDependency)mergedDependency).getFiles()) { + library.addPath(LibraryPathType.BINARY, file.getAbsolutePath()); + } + + ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); + } + if (mergedDependency instanceof UnresolvedExternalDependency) { + final LibraryLevel level = LibraryLevel.PROJECT; + String libraryName = mergedDependency.getId().getPresentableName(); + final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName, true); + LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); + libraryDependencyData.setScope(dependencyScope); + final String failureMessage = ((UnresolvedExternalDependency)mergedDependency).getFailureMessage(); + if (failureMessage != null) { + library.addPath(LibraryPathType.BINARY, failureMessage); + } + ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); + linkProjectLibrary(ideProject, library); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java index 918dc19b32d7..96b7e0345d09 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java @@ -368,6 +368,7 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver libraryPaths = libraryData.getPaths(LibraryPathType.BINARY); if (libraryPaths.isEmpty()) continue; + if(StringUtil.isNotEmpty(libraryData.getExternalName())) continue; final LinkedList unprocessedPaths = ContainerUtil.newLinkedList(libraryPaths); while (!unprocessedPaths.isEmpty()) { diff --git a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ExternalMultiLibraryDependency.java b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ExternalMultiLibraryDependency.java new file mode 100644 index 000000000000..079b1c3fb02c --- /dev/null +++ b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ExternalMultiLibraryDependency.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.gradle.model; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Collection; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 7/14/2014 + */ +public interface ExternalMultiLibraryDependency extends ExternalDependency { + /** + * Returns the binary files for this dependency. + * + * @return binary file + */ + @NotNull + Collection getFiles(); + + /** + * Returns the source directories/archives for this dependency. + * + * @return The source files. + */ + @NotNull + Collection getSources(); + + /** + * Returns the Javadoc directories/archives for this dependency. + * + * @return The Javadoc files. + */ + @NotNull + Collection getJavadoc(); +} diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/model/DefaultExternalMultiLibraryDependency.java b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/model/DefaultExternalMultiLibraryDependency.java new file mode 100644 index 000000000000..ee47a9f07c92 --- /dev/null +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/model/DefaultExternalMultiLibraryDependency.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.gradle.model; + +import com.google.common.base.Objects; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Collection; +import java.util.LinkedHashSet; + +/** + * @author Vladislav.Soroka + * @since 12/24/2014 + */ +public class DefaultExternalMultiLibraryDependency extends AbstractExternalDependency implements ExternalMultiLibraryDependency { + + private static final long serialVersionUID = 1L; + private Collection files = new LinkedHashSet(); + private Collection sources = new LinkedHashSet(); + private Collection javadocs = new LinkedHashSet(); + + public DefaultExternalMultiLibraryDependency() { + } + + public DefaultExternalMultiLibraryDependency(ExternalMultiLibraryDependency dependency) { + super(dependency); + files = dependency.getFiles(); + sources = dependency.getSources(); + javadocs = dependency.getJavadoc(); + } + + @NotNull + @Override + public Collection getFiles() { + return files; + } + + @NotNull + @Override + public Collection getSources() { + return sources; + } + + @NotNull + @Override + public Collection getJavadoc() { + return javadocs; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DefaultExternalMultiLibraryDependency)) return false; + if (!super.equals(o)) return false; + DefaultExternalMultiLibraryDependency that = (DefaultExternalMultiLibraryDependency)o; + return Objects.equal(files, that.files); + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), files); + } + + @Override + public String toString() { + return "library '" + files + '\''; + } +} diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.groovy index b131b1cd13e2..115e452de067 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.groovy +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.groovy @@ -226,9 +226,6 @@ class DependencyResolverImpl implements DependencyResolver { runtimeClasspathFiles -= sourceSet.output.files compileClasspathFiles -= sourceSet.output.files - mapFileDependencies(runtimeClasspathFiles, runtimeScope, result) - mapFileDependencies(compileClasspathFiles, compileScope, result) - Multimap resolvedDependenciesMap = ArrayListMultimap.create() Project rootProject = myProject.rootProject @@ -293,6 +290,28 @@ class DependencyResolverImpl implements DependencyResolver { runtimeClasspathFiles.removeAll(resolvedDependenciesMap.get(compileScope)) runtimeClasspathFiles.removeAll(resolvedDependenciesMap.get(providedScope)) + Collection fileDependencies = new ArrayList<>() + mapFileDependencies(runtimeClasspathFiles, runtimeScope, fileDependencies) + mapFileDependencies(compileClasspathFiles, compileScope, fileDependencies) + + fileDependencies.each { + def dependency = it + def scope = dependency.scope + order = -1; + if (dependency instanceof ExternalLibraryDependency) { + def classpathOrderMap = scope == compileScope ? compileClasspathOrder : + scope == runtimeScope ? runtimeClasspathOrder : null + if (classpathOrderMap) { + def fileOrder = classpathOrderMap.get(dependency.file) + order = fileOrder != null ? fileOrder : -1 + } + } + if (dependency instanceof AbstractExternalDependency) { + dependency.classpathOrder = order + } + } + result.addAll(fileDependencies) + if (!compileClasspathFiles.isEmpty()) { final compileClasspathFilesDependency = new DefaultFileCollectionDependency(compileClasspathFiles) compileClasspathFilesDependency.scope = compileScope @@ -388,15 +407,27 @@ class DependencyResolverImpl implements DependencyResolver { @Nullable ExternalLibraryDependency resolveLibraryByPath(File file, String scope) { File modules2Dir = new File(myProject.gradle.gradleUserHomeDir, "caches/modules-2/files-2.1"); - def modules2Path = modules2Dir.canonicalPath - return resolveLibraryByPath(file, modules2Path, scope) + return resolveLibraryByPath(file, modules2Dir, scope) } @Nullable - static ExternalLibraryDependency resolveLibraryByPath(File file, String modules2Path, String scope) { + static ExternalLibraryDependency resolveLibraryByPath(File file, File modules2Dir, String scope) { File sourcesFile = null; - if (file.canonicalPath.startsWith(modules2Path)) { - def parentFile = file.parentFile?.parentFile + def modules2Path = modules2Dir.canonicalPath + def filePath = file.canonicalPath + if (filePath.startsWith(modules2Path)) { + List parents = new ArrayList<>() + File parent = file.parentFile; + while(parent && !parent.name.equals(modules2Dir.name)) { + parents.add(parent) + parent = parent.parentFile + } + + def groupDir = parents.get(parents.size() - 1) + def artifactDir = parents.get(parents.size() - 2) + def versionDir = parents.get(parents.size() - 3) + + def parentFile = versionDir if (parentFile != null) { def hashDirs = parentFile.listFiles() if (hashDirs != null) { @@ -414,9 +445,6 @@ class DependencyResolverImpl implements DependencyResolver { } } - def versionDir = parentFile - def artifactDir = versionDir.parentFile - def groupDir = artifactDir.parentFile def packaging = resolvePackagingType(file); def classifier = resolveClassifier(artifactDir.name, versionDir.name, file); return new DefaultExternalLibraryDependency( @@ -438,10 +466,9 @@ class DependencyResolverImpl implements DependencyResolver { def mapFileDependencies(Set fileDependencies, String scope, Collection dependencies) { File modules2Dir = new File(myProject.gradle.gradleUserHomeDir, "caches/modules-2/files-2.1"); - def modules2Path = modules2Dir.canonicalPath List toRemove = new ArrayList() for (File file : fileDependencies) { - def libraryDependency = resolveLibraryByPath(file, modules2Path, scope) + def libraryDependency = resolveLibraryByPath(file, modules2Dir, scope) if (libraryDependency) { dependencies.add(libraryDependency) toRemove.add(file) From 67dd75faa9f2ff8f9238501b8ccbb5c6984d24e0 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 22 Oct 2015 12:56:26 +0300 Subject: [PATCH 03/17] typo --- .../src/com/intellij/debugger/engine/DebugProcess.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java index 7a3624b1d16a..4fce97015a48 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,7 +56,7 @@ public interface DebugProcess { /** * The usual place to call this method is vmAttachedEvent. No additional actions are needed in this case. * If position manager is appended later, when DebugSession is up and running, one might need to call BreakpointManager.updateAllRequests() - * to ensure that just adedd position manager was considered when creating breakpoint requests + * to ensure that just added position manager was considered when creating breakpoint requests * @param positionManager to be appended */ void appendPositionManager(PositionManager positionManager); From 8a150952ce060ff485a4df426f84e99c0e93b945 Mon Sep 17 00:00:00 2001 From: Andrey Vokin Date: Thu, 22 Oct 2015 13:20:19 +0300 Subject: [PATCH 04/17] RUBY-17264 Generate xml tag spoils html tag and throws exception --- .../xml/actions/GenerateXmlTagAction.java | 35 +++++++++++++++++++ .../xml/actions/GenerateXmlTagTest.java | 4 +++ .../try_to_generate_in_tag_name.xml | 7 ++++ .../try_to_generate_in_tag_name_after.xml | 7 ++++ 4 files changed, 53 insertions(+) create mode 100644 xml/tests/testData/generateTag/try_to_generate_in_tag_name.xml create mode 100644 xml/tests/testData/generateTag/try_to_generate_in_tag_name_after.xml diff --git a/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java b/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java index bf58ebfa2cd6..7f9a8aa7d29d 100644 --- a/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java +++ b/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java @@ -303,9 +303,44 @@ public class GenerateXmlTagAction extends SimpleCodeInsightAction { } } + private static boolean isInsideTagBody(@NotNull Editor editor, @NotNull PsiFile file) { + PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); + while (element != null && !(element.getParent() instanceof XmlTag)) { + element = element.getParent(); + } + if (element == null) { + return false; + } + + if (element.getNode().getElementType() == XmlTokenType.XML_START_TAG_START) { + return true; + } else { + PsiElement left = element.getPrevSibling(); + while (left != null && left.getNode().getElementType() != XmlTokenType.XML_TAG_END) { + left = left.getPrevSibling(); + } + if (left == null) { + return false; + } + PsiElement right = element.getNextSibling(); + while (right != null && right.getNode().getElementType() != XmlTokenType.XML_END_TAG_START) { + right = right.getNextSibling(); + } + if (right == null) { + return false; + } + return true; + } + } + @Override protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { if (!(file instanceof XmlFile)) return false; + + if (!isInsideTagBody(editor, file)) { + return false; + } + XmlTag contextTag = getContextTag(editor, file); return contextTag != null && contextTag.getDescriptor() != null; } diff --git a/xml/tests/src/com/intellij/xml/actions/GenerateXmlTagTest.java b/xml/tests/src/com/intellij/xml/actions/GenerateXmlTagTest.java index 170a3a8318e1..239966e4ef81 100644 --- a/xml/tests/src/com/intellij/xml/actions/GenerateXmlTagTest.java +++ b/xml/tests/src/com/intellij/xml/actions/GenerateXmlTagTest.java @@ -70,6 +70,10 @@ public class GenerateXmlTagTest extends LightPlatformCodeInsightFixtureTestCase doTest("initParam.xml", "context-param"); } + public void testInTagName() { + doTest("try_to_generate_in_tag_name.xml", "context-param"); + } + private void doTest(String file, String tagName) { GenerateXmlTagAction.TEST_THREAD_LOCAL.set(tagName); CodeInsightTestUtil.doActionTest(new GenerateXmlTagAction(), file, myFixture); diff --git a/xml/tests/testData/generateTag/try_to_generate_in_tag_name.xml b/xml/tests/testData/generateTag/try_to_generate_in_tag_name.xml new file mode 100644 index 000000000000..0e2d74a8557b --- /dev/null +++ b/xml/tests/testData/generateTag/try_to_generate_in_tag_name.xml @@ -0,0 +1,7 @@ + + + > + + + + \ No newline at end of file diff --git a/xml/tests/testData/generateTag/try_to_generate_in_tag_name_after.xml b/xml/tests/testData/generateTag/try_to_generate_in_tag_name_after.xml new file mode 100644 index 000000000000..1cd59beb9c37 --- /dev/null +++ b/xml/tests/testData/generateTag/try_to_generate_in_tag_name_after.xml @@ -0,0 +1,7 @@ + + +
+ +
+ + \ No newline at end of file From c099a7f797335aee81624d64c72d16d2133c2a7c Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 22 Oct 2015 13:24:30 +0300 Subject: [PATCH 05/17] guava type migration: proper recognition of PsiMethodReference type => migration for variable references --- .../typeMigration/TypeEvaluator.java | 9 +++- .../TypeMigrationStatementProcessor.java | 11 ++-- .../src/META-INF/TypeMigration.xml | 1 + .../guava/BaseGuavaTypeConversionRule.java | 23 ++++++-- .../GuavaFluentIterableConversionRule.java | 5 +- .../guava/GuavaFunctionConversionRule.java | 11 ++++ .../guava/GuavaOptionalConversionRule.java | 7 +++ .../guava/GuavaPredicateConversionRule.java | 11 ++++ .../guava/IterableStreamConversionRule.java | 52 +++++++++++++++++++ .../inspections/GuavaInspectionTest.java | 8 +++ ...vertFluentIterableAsIterableParameter.java | 13 +++++ ...uentIterableAsIterableParameter_after.java | 14 +++++ .../guava/convertFunctionAsParameter.java | 15 ++++++ .../convertFunctionAsParameter_after.java | 11 ++++ 14 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/IterableStreamConversionRule.java create mode 100644 java/typeMigration/testData/inspections/guava/convertFluentIterableAsIterableParameter.java create mode 100644 java/typeMigration/testData/inspections/guava/convertFluentIterableAsIterableParameter_after.java create mode 100644 java/typeMigration/testData/inspections/guava/convertFunctionAsParameter.java create mode 100644 java/typeMigration/testData/inspections/guava/convertFunctionAsParameter_after.java diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java index 4e4f078c8944..9337eb69a55b 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java @@ -233,12 +233,19 @@ public class TypeEvaluator { } } } + else if (expr instanceof PsiFunctionalExpression) { + final PsiType functionalInterfaceType = ((PsiFunctionalExpression)expr).getFunctionalInterfaceType(); + if (functionalInterfaceType != null) { + return functionalInterfaceType; + } + } else if (expr instanceof PsiReferenceExpression) { final PsiType type = evaluateReferenceExpressionType(expr); if (type != null) { return PsiImplUtil.normalizeWildcardTypeByPosition(type, expr); } - } else if (expr instanceof PsiSuperExpression) { + } + else if (expr instanceof PsiSuperExpression) { final PsiClass psiClass = PsiTreeUtil.getParentOfType(expr, PsiClass.class); if (psiClass != null) { final PsiClass superClass = psiClass.getSuperClass(); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java index 3431b403a8b5..22eec71da3b1 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java @@ -19,6 +19,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; +import com.intellij.psi.impl.PsiSubstitutorImpl; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; @@ -26,6 +27,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo; +import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import java.util.Collections; @@ -525,9 +527,12 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { public TypeView(PsiVariable var, PsiSubstitutor varSubstitutor, PsiSubstitutor evalSubstitutor) { myOriginType = varSubstitutor != null ? varSubstitutor.substitute(var.getType()) : var.getType(); - myType = evalSubstitutor != null - ? evalSubstitutor.substitute(myTypeEvaluator.getType(var)) - : myTypeEvaluator.getType(var); + + Map realMap = new HashMap(); + if (varSubstitutor != null) realMap.putAll(varSubstitutor.getSubstitutionMap()); + if (evalSubstitutor != null) realMap.putAll(evalSubstitutor.getSubstitutionMap()); + + myType = PsiSubstitutorImpl.createSubstitutor(realMap).substitute(myTypeEvaluator.getType(var)); myChanged = (myOriginType == null || myType == null) ? false : !myType.equals(myOriginType); } diff --git a/java/typeMigration/src/META-INF/TypeMigration.xml b/java/typeMigration/src/META-INF/TypeMigration.xml index 082c3ba802d5..876d0555bf7b 100644 --- a/java/typeMigration/src/META-INF/TypeMigration.xml +++ b/java/typeMigration/src/META-INF/TypeMigration.xml @@ -13,6 +13,7 @@ + com.intellij.refactoring.typeMigration.intentions.ConvertFieldToAtomicIntention Java/Concurrency diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/BaseGuavaTypeConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/BaseGuavaTypeConversionRule.java index f287626a41d3..9c227fb09d33 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/BaseGuavaTypeConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/BaseGuavaTypeConversionRule.java @@ -57,6 +57,12 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule { return null; }; + @Nullable + protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression, + @NotNull PsiVariable psiVariable) { + return null; + } + @NotNull public abstract String ruleFromClass(); @@ -70,7 +76,7 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule { PsiMember member, PsiExpression context, TypeMigrationLabeler labeler) { - if (from != null && to != null && !canConvert(from, to)) { + if (from != null && to != null && !canConvert(from, to, ruleFromClass(), ruleToClass())) { return null; } if (member instanceof PsiMethod) { @@ -92,10 +98,19 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule { }; } } + else if (context instanceof PsiReferenceExpression) { + final PsiElement resolvedElement = ((PsiReferenceExpression)context).resolve(); + if (resolvedElement instanceof PsiVariable) { + return findConversionForVariableReference((PsiReferenceExpression)context, (PsiVariable)resolvedElement); + } + } return null; } - private boolean canConvert(PsiType from, PsiType to) { + public static boolean canConvert(@Nullable PsiType from, + @Nullable PsiType to, + @NotNull String fromClassName, + @NotNull String toClassName) { if (!(from instanceof PsiClassType)) { return false; } @@ -108,13 +123,13 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule { if (fromClass instanceof PsiAnonymousClass) { fromClass = ((PsiAnonymousClass)fromClass).getBaseClassType().resolve(); } - if (fromClass == null || !ruleFromClass().equals(fromClass.getQualifiedName())) { + if (fromClass == null || !fromClassName.equals(fromClass.getQualifiedName())) { return false; } final PsiClassType.ClassResolveResult toResolveResult = ((PsiClassType)to).resolveGenerics(); final PsiClass toClass = toResolveResult.getElement(); - if (toClass == null || !ruleToClass().equals(toClass.getQualifiedName())) { + if (toClass == null || !toClassName.equals(toClass.getQualifiedName())) { return false; } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java index e9ef2cf4f774..a90f7639be1a 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java @@ -45,8 +45,9 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu public static final Set CHAIN_HEAD_METHODS = ContainerUtil.newHashSet("from", "of"); public static final String FLUENT_ITERABLE = "com.google.common.collect.FluentIterable"; + public static final String STREAM_COLLECT_TO_LIST = "$it$.collect(java.util.stream.Collectors.toList())"; - private static class TypeConversionDescriptorFactory { + static class TypeConversionDescriptorFactory { private final String myStringToReplace; private final String myReplaceByString; private final boolean myWithLambdaParameter; @@ -103,7 +104,7 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu DESCRIPTORS_MAP.put("toMap", new TypeConversionDescriptorFactory("$it$.toMap($f$)", "$it$.collect(java.util.stream.Collectors.toMap(java.util.function.Function.identity(), $f$))", true)); - DESCRIPTORS_MAP.put("toList", new TypeConversionDescriptorFactory("$it$.toList()", "$it$.collect(java.util.stream.Collectors.toList())", false)); + DESCRIPTORS_MAP.put("toList", new TypeConversionDescriptorFactory("$it$.toList()", STREAM_COLLECT_TO_LIST, false)); DESCRIPTORS_MAP.put("toSet", new TypeConversionDescriptorFactory("$it$.toSet()", "$it$.collect(java.util.stream.Collectors.toSet())", false)); DESCRIPTORS_MAP.put("toSortedList", new TypeConversionDescriptorFactory("$it$.toSortedList($c$)", "$it$.sorted($c$).collect(java.util.stream.Collectors.toList())", false)); DESCRIPTORS_MAP.put("toSortedSet", new TypeConversionDescriptorFactory("$it$.toSortedSet($c$)", "$it$.sorted($c$).collect(java.util.stream.Collectors.toSet())", false)); diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFunctionConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFunctionConversionRule.java index e36cfdb916e5..5bf7a74ee819 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFunctionConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFunctionConversionRule.java @@ -15,8 +15,12 @@ */ package com.intellij.refactoring.typeMigration.rules.guava; +import com.intellij.psi.PsiReferenceExpression; +import com.intellij.psi.PsiVariable; +import com.intellij.refactoring.typeMigration.TypeConversionDescriptor; import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Map; @@ -31,6 +35,13 @@ public class GuavaFunctionConversionRule extends BaseGuavaTypeConversionRule { descriptorsMap.put("apply", new FunctionalInterfaceTypeConversionDescriptor("apply", "apply")); } + @Nullable + @Override + protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression, + @NotNull PsiVariable psiVariable) { + return new TypeConversionDescriptor("$f$", "$f$::apply"); + } + @NotNull @Override public String ruleFromClass() { diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaOptionalConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaOptionalConversionRule.java index 1559ae812f78..31244db21f5c 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaOptionalConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaOptionalConversionRule.java @@ -88,6 +88,13 @@ public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule { return GuavaFluentIterableConversionRule.buildCompoundDescriptor((PsiMethodCallExpression) context, to, labeler); } + @Nullable + @Override + protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression, + @NotNull PsiVariable psiVariable) { + return new TypeConversionDescriptor("$o$", "$o$::get"); + } + private PsiClass getParameterClass(PsiMethod method) { final PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameters.length != 1) { diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicateConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicateConversionRule.java index 0a70e97f5558..3fdb2e50123d 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicateConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicateConversionRule.java @@ -15,8 +15,12 @@ */ package com.intellij.refactoring.typeMigration.rules.guava; +import com.intellij.psi.PsiReferenceExpression; +import com.intellij.psi.PsiVariable; +import com.intellij.refactoring.typeMigration.TypeConversionDescriptor; import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Map; @@ -32,6 +36,13 @@ public class GuavaPredicateConversionRule extends BaseGuavaTypeConversionRule { descriptorsMap.put("apply", new FunctionalInterfaceTypeConversionDescriptor("apply", "test")); } + @Nullable + @Override + protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression, + @NotNull PsiVariable psiVariable) { + return new TypeConversionDescriptor("$p$", "$p$::test"); + } + @NotNull @Override public String ruleFromClass() { diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/IterableStreamConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/IterableStreamConversionRule.java new file mode 100644 index 000000000000..fc4448e7d376 --- /dev/null +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/IterableStreamConversionRule.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.refactoring.typeMigration.rules.guava; + +import com.intellij.codeInspection.java18StreamApi.StreamApiConstants; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTypesUtil; +import com.intellij.refactoring.typeMigration.TypeConversionDescriptor; +import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase; +import com.intellij.refactoring.typeMigration.TypeMigrationLabeler; +import com.intellij.refactoring.typeMigration.rules.TypeConversionRule; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Batkovich + */ +public class IterableStreamConversionRule extends TypeConversionRule { + @Nullable + @Override + public TypeConversionDescriptorBase findConversion(PsiType from, + PsiType to, + PsiMember member, + PsiExpression context, + TypeMigrationLabeler labeler) { + if (BaseGuavaTypeConversionRule + .canConvert(from, to, CommonClassNames.JAVA_LANG_ITERABLE, StreamApiConstants.JAVA_UTIL_STREAM_STREAM)) { + if (context instanceof PsiReferenceExpression) { + final PsiElement resolved = ((PsiReferenceExpression)context).resolve(); + if (resolved instanceof PsiVariable) { + final PsiClass aClass = PsiTypesUtil.getPsiClass(((PsiVariable)resolved).getType()); + if (aClass != null && GuavaFluentIterableConversionRule.FLUENT_ITERABLE.equals(aClass.getQualifiedName())) { + return new TypeConversionDescriptor("$it$", GuavaFluentIterableConversionRule.STREAM_COLLECT_TO_LIST); + } + } + } + } + return null; + } +} diff --git a/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java b/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java index b9e0f4fc2ad3..4fa31f9ad75f 100644 --- a/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java +++ b/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java @@ -154,6 +154,14 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase { doTest(); } + public void testConvertFluentIterableAsIterableParameter() { + doTest(); + } + + public void testConvertFunctionAsParameter() { + doTest(); + } + private void doTestNoQuickFixes(final Class... quickFixesClasses) { myFixture.configureByFile(getTestName(true) + ".java"); myFixture.enableInspections(new GuavaInspection()); diff --git a/java/typeMigration/testData/inspections/guava/convertFluentIterableAsIterableParameter.java b/java/typeMigration/testData/inspections/guava/convertFluentIterableAsIterableParameter.java new file mode 100644 index 000000000000..a6973f0a7371 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/convertFluentIterableAsIterableParameter.java @@ -0,0 +1,13 @@ +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Iterables; + +import java.util.ArrayList; + +public class Main16 { + void m() { + FluentIterable it = FluentIterable.from(new ArrayList()).transform(s -> s); + + //read-only method with Iterable parameter + Iterables.cycle(it); + } +} diff --git a/java/typeMigration/testData/inspections/guava/convertFluentIterableAsIterableParameter_after.java b/java/typeMigration/testData/inspections/guava/convertFluentIterableAsIterableParameter_after.java new file mode 100644 index 000000000000..e96ac4e85471 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/convertFluentIterableAsIterableParameter_after.java @@ -0,0 +1,14 @@ +import com.google.common.collect.Iterables; + +import java.util.ArrayList; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Main16 { + void m() { + Stream it = new ArrayList().stream().map(s -> s); + + //read-only method with Iterable parameter + Iterables.cycle(it.collect(Collectors.toList())); + } +} diff --git a/java/typeMigration/testData/inspections/guava/convertFunctionAsParameter.java b/java/typeMigration/testData/inspections/guava/convertFunctionAsParameter.java new file mode 100644 index 000000000000..8160691da866 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/convertFunctionAsParameter.java @@ -0,0 +1,15 @@ +import com.google.common.base.Function; +import com.google.common.base.Functions; + +public class Main16 { + void m() { + Function f = new Function() { + @Override + public String apply(String s) { + return s.substring(12) + "12"; + } + }; + + Functions.compose(f, f); + } +} diff --git a/java/typeMigration/testData/inspections/guava/convertFunctionAsParameter_after.java b/java/typeMigration/testData/inspections/guava/convertFunctionAsParameter_after.java new file mode 100644 index 000000000000..1adeffafd2a7 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/convertFunctionAsParameter_after.java @@ -0,0 +1,11 @@ +import com.google.common.base.Functions; + +import java.util.function.Function; + +public class Main16 { + void m() { + Function f = s -> s.substring(12) + "12"; + + Functions.compose(f::apply, f::apply); + } +} From b4681502612f16c3da23b0749b88363ba8a0d0e2 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 16:46:25 +0300 Subject: [PATCH 06/17] EA-74877 - IAE: DeclarationSearcher.a --- .../quickfix/ConvertReturnStatementsVisitor.java | 14 +++++++------- .../impl/quickfix/DeclarationSearcher.java | 11 +++++------ .../impl/quickfix/MethodReturnTypeFix.java | 8 ++++---- .../src/com/intellij/psi/util/PsiTypesUtil.java | 16 +++++----------- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertReturnStatementsVisitor.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertReturnStatementsVisitor.java index aed8f23003bf..2ef03c5f9ae4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertReturnStatementsVisitor.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertReturnStatementsVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,16 +27,16 @@ import org.jetbrains.annotations.Nullable; import java.util.List; class ConvertReturnStatementsVisitor implements ReturnStatementsVisitor { - private final PsiElementFactory myFactory; - private final PsiMethod myMethod; - private final DeclarationSearcher mySearcher; + @NotNull private final PsiElementFactory myFactory; + @NotNull private final PsiMethod myMethod; + @NotNull private final DeclarationSearcher mySearcher; + @NotNull private final String myDefaultValue; private PsiReturnStatement myLatestReturn; - private final String myDefaultValue; - public ConvertReturnStatementsVisitor(final PsiElementFactory factory, final PsiMethod method, final PsiType targetType) { + ConvertReturnStatementsVisitor(@NotNull PsiElementFactory factory, @NotNull PsiMethod method, @NotNull PsiType targetType) { myFactory = factory; myMethod = method; - mySearcher = new DeclarationSearcher(myMethod, targetType); + mySearcher = new DeclarationSearcher(method, targetType); myDefaultValue = PsiTypesUtil.getDefaultValueOfType(targetType); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeclarationSearcher.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeclarationSearcher.java index b31a533bb5df..3382671e6d63 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeclarationSearcher.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeclarationSearcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,17 +22,15 @@ import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; -public class DeclarationSearcher { +class DeclarationSearcher { private final PsiMethod myMethod; private final PsiType myTargetType; - private final Map cache; + private final Map cache = new HashMap(); - public DeclarationSearcher(final PsiMethod method, final PsiType targetType) { + DeclarationSearcher(@NotNull PsiMethod method, @NotNull PsiType targetType) { myMethod = method; myTargetType = targetType; - - cache = new HashMap(); } @Nullable @@ -57,6 +55,7 @@ public class DeclarationSearcher { @Nullable private PsiVariable getLocalDeclaration(@NotNull PsiElement endPositionElement) { final PsiElement parent = endPositionElement.getParent(); + if (parent == null) return null; // reuse of cache is possible IF requests are done up-to-down. otherwise - not first declaration can be returned final PsiVariable cachedCandidate = cache.get(parent); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java index 0a016a96dfb8..5566d086d1fc 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java @@ -145,15 +145,15 @@ public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiEle // to clearly separate data private static class ReturnStatementAdder { - private final PsiElementFactory factory; - private final PsiType myTargetType; + @NotNull private final PsiElementFactory factory; + @NotNull private final PsiType myTargetType; private ReturnStatementAdder(@NotNull final PsiElementFactory factory, @NotNull final PsiType targetType) { this.factory = factory; myTargetType = targetType; } - public PsiReturnStatement addReturnForMethod(final PsiFile file, final PsiMethod method) { + private PsiReturnStatement addReturnForMethod(final PsiFile file, final PsiMethod method) { final PsiModifierList modifiers = method.getModifierList(); if (modifiers.hasModifierProperty(PsiModifier.ABSTRACT) || method.getBody() == null) { return null; @@ -170,7 +170,7 @@ public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiEle return null; //must be an error } PsiReturnStatement returnStatement; - if (controlFlow != null && ControlFlowUtil.processReturns(controlFlow, visitor)) { + if (ControlFlowUtil.processReturns(controlFlow, visitor)) { // extra return statement not needed // get latest modified return statement and select... returnStatement = visitor.getLatestReturn(); diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java index 9ee81fc5a228..ec2878518f47 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,6 +57,7 @@ public class PsiTypesUtil { private PsiTypesUtil() { } + @NotNull public static String getDefaultValueOfType(PsiType type) { if (type instanceof PsiArrayType) { int count = type.getArrayDimensions() - 1; @@ -79,17 +80,10 @@ public class PsiTypesUtil { } return buffer.toString(); } - else if (type instanceof PsiPrimitiveType) { - if (PsiType.BOOLEAN.equals(type)) { - return PsiKeyword.FALSE; - } - else { - return "0"; - } - } - else { - return PsiKeyword.NULL; + if (type instanceof PsiPrimitiveType) { + return PsiType.BOOLEAN.equals(type) ? PsiKeyword.FALSE : "0"; } + return PsiKeyword.NULL; } /** From cfa73f76ce0556d846ff04f0acb52fb688db2bf4 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 17:53:19 +0300 Subject: [PATCH 07/17] EA-68554 - IAE: TypeConversionUtil.isAssignable --- java/java-impl/src/com/intellij/slicer/SliceUtil.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/slicer/SliceUtil.java b/java/java-impl/src/com/intellij/slicer/SliceUtil.java index 923f9508c0b4..fb2cf9f760f3 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUtil.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUtil.java @@ -319,7 +319,9 @@ class SliceUtil { PsiExpression rExpression = ((PsiAssignmentExpression)parentExpr).getRExpression(); PsiType rtype = rExpression.getType(); PsiType ftype = field.getType(); - if (TypeConversionUtil.isAssignable(parentSubstitutor.substitute(ftype), parentSubstitutor.substitute(rtype))) { + PsiType subFType = parentSubstitutor.substitute(ftype); + PsiType subRType = parentSubstitutor.substitute(rtype); + if (subFType != null && subRType != null && TypeConversionUtil.isAssignable(subFType, subRType)) { return handToProcessor(rExpression, processor, parent, parentSubstitutor, parent.indexNesting, ""); } } From 43e2a15e4d3e3c26bb45e263271f21c29c908cf3 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 17:56:16 +0300 Subject: [PATCH 08/17] EA-68276 - assert: ComponentManagerImpl.getPicoContainer --- .../intellij/codeInsight/daemon/impl/PassExecutorService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java index 212564a81c7e..7d5ae036105f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java @@ -440,7 +440,7 @@ class PassExecutorService implements Disposable { return; } - if (!myUpdateProgress.isCanceled()) { + if (!myUpdateProgress.isCanceled() && !myProject.isDisposed()) { myPass.collectInformation(myUpdateProgress); } } From a3d0d074d2ed590341ba2a477e06b4244177989c Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 18:15:05 +0300 Subject: [PATCH 09/17] cleanup --- .../com/intellij/ide/PsiCopyPasteManager.java | 86 +++++---- .../ide/actions/SearchEverywhereAction.java | 166 +++++++++--------- 2 files changed, 125 insertions(+), 127 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java index d94bc7bbdb9f..af69bbe64074 100644 --- a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java +++ b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package com.intellij.ide; import com.intellij.ide.dnd.LinuxDragAndDropSupport; -import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; @@ -25,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerAdapter; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.LocalFileSystem; @@ -162,33 +162,29 @@ public class PsiCopyPasteManager { public PsiElement[] getElements() { if (myElements == null) return PsiElement.EMPTY_ARRAY; - int validElementsCount = 0; + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + int validElementsCount = 0; + for (PsiElement element : myElements) { + if (element.isValid()) { + validElementsCount++; + } + } - final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock(); - try { - for (PsiElement element : myElements) { - if (element.isValid()) { - validElementsCount++; + if (validElementsCount != myElements.length) { + PsiElement[] validElements = new PsiElement[validElementsCount]; + int j = 0; + for (PsiElement element : myElements) { + if (element.isValid()) { + validElements[j++] = element; + } + } + + myElements = validElements; } } - - if (validElementsCount == myElements.length) { - return myElements; - } - - PsiElement[] validElements = new PsiElement[validElementsCount]; - int j=0; - for (PsiElement element : myElements) { - if (element.isValid()) { - validElements[j++] = element; - } - } - - myElements = validElements; - } - finally { - token.finish(); - } + }); return myElements; } @@ -261,33 +257,31 @@ public class PsiCopyPasteManager { @Nullable private String getDataAsText() { - final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock(); - try { - final List names = new ArrayList(); - for (PsiElement element : myDataProxy.getElements()) { - if (element instanceof PsiNamedElement) { - String name = ((PsiNamedElement)element).getName(); - if (name != null) { - names.add(name); + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + final List names = new ArrayList(); + for (PsiElement element : myDataProxy.getElements()) { + if (element instanceof PsiNamedElement) { + String name = ((PsiNamedElement)element).getName(); + if (name != null) { + names.add(name); + } } } + return names.isEmpty() ? null : StringUtil.join(names, "\n"); } - return names.isEmpty() ? null : StringUtil.join(names, "\n"); - } - finally { - token.finish(); - } + }); } @Nullable private List getDataAsFileList() { - final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock(); - try { - return asFileList(myDataProxy.getElements()); - } - finally { - token.finish(); - } + return ApplicationManager.getApplication().runReadAction(new Computable>() { + @Override + public List compute() { + return asFileList(myDataProxy.getElements()); + } + }); } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 480dfca26df7..309c78e113a1 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -1166,103 +1166,107 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } @Override - protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { + protected void customizeCellRenderer(JList list, final Object value, int index, final boolean selected, boolean hasFocus) { setPaintFocusBorder(false); setIcon(EmptyIcon.ICON_16); - AccessToken token = ApplicationManager.getApplication().acquireReadActionLock(); - try { - if (value instanceof PsiElement) { - String name = myClassModel.getElementName(value); - assert name != null; - append(name); - } else if (value instanceof ChooseRunConfigurationPopup.ItemWrapper) { - final ChooseRunConfigurationPopup.ItemWrapper wrapper = (ChooseRunConfigurationPopup.ItemWrapper)value; - append(wrapper.getText()); - setIcon(wrapper.getIcon()); - setLocationString(ourShiftIsPressed.get() ? "Run" : "Debug"); - myLocationIcon = ourShiftIsPressed.get() ? AllIcons.Toolwindows.ToolWindowRun : AllIcons.Toolwindows.ToolWindowDebugger; - } else if (isVirtualFile(value)) { - final VirtualFile file = (VirtualFile)value; - if (file instanceof VirtualFilePathWrapper) { - append(((VirtualFilePathWrapper)file).getPresentablePath()); - } else { - append(file.getName()); + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (value instanceof PsiElement) { + String name = myClassModel.getElementName(value); + assert name != null; + append(name); } - setIcon(IconUtil.getIcon(file, Iconable.ICON_FLAG_READ_STATUS, myProject)); - } - else if (isActionValue(value)) { - final GotoActionModel.ActionWrapper actionWithParentGroup = value instanceof GotoActionModel.ActionWrapper ? (GotoActionModel.ActionWrapper)value : null; - final AnAction anAction = actionWithParentGroup == null ? (AnAction)value : actionWithParentGroup.getAction(); - final Presentation templatePresentation = anAction.getTemplatePresentation(); - Icon icon = templatePresentation.getIcon(); - if (anAction instanceof ActivateToolWindowAction) { - final String id = ((ActivateToolWindowAction)anAction).getToolWindowId(); - ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(id); - if (toolWindow != null) { - icon = toolWindow.getIcon(); + else if (value instanceof ChooseRunConfigurationPopup.ItemWrapper) { + final ChooseRunConfigurationPopup.ItemWrapper wrapper = (ChooseRunConfigurationPopup.ItemWrapper)value; + append(wrapper.getText()); + setIcon(wrapper.getIcon()); + setLocationString(ourShiftIsPressed.get() ? "Run" : "Debug"); + myLocationIcon = ourShiftIsPressed.get() ? AllIcons.Toolwindows.ToolWindowRun : AllIcons.Toolwindows.ToolWindowDebugger; + } + else if (isVirtualFile(value)) { + final VirtualFile file = (VirtualFile)value; + if (file instanceof VirtualFilePathWrapper) { + append(((VirtualFilePathWrapper)file).getPresentablePath()); } + else { + append(file.getName()); + } + setIcon(IconUtil.getIcon(file, Iconable.ICON_FLAG_READ_STATUS, myProject)); } + else if (isActionValue(value)) { + final GotoActionModel.ActionWrapper actionWithParentGroup = + value instanceof GotoActionModel.ActionWrapper ? (GotoActionModel.ActionWrapper)value : null; + final AnAction anAction = actionWithParentGroup == null ? (AnAction)value : actionWithParentGroup.getAction(); + final Presentation templatePresentation = anAction.getTemplatePresentation(); + Icon icon = templatePresentation.getIcon(); + if (anAction instanceof ActivateToolWindowAction) { + final String id = ((ActivateToolWindowAction)anAction).getToolWindowId(); + ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(id); + if (toolWindow != null) { + icon = toolWindow.getIcon(); + } + } - append(templatePresentation.getText()); - if (actionWithParentGroup != null) { - final String groupName = actionWithParentGroup.getGroupName(); + append(templatePresentation.getText()); + if (actionWithParentGroup != null) { + final String groupName = actionWithParentGroup.getGroupName(); + if (!StringUtil.isEmpty(groupName)) { + setLocationString(groupName); + } + } + + final String groupName = actionWithParentGroup == null ? null : actionWithParentGroup.getGroupName(); if (!StringUtil.isEmpty(groupName)) { setLocationString(groupName); } - } - - final String groupName = actionWithParentGroup == null ? null : actionWithParentGroup.getGroupName(); - if (!StringUtil.isEmpty(groupName)) { - setLocationString(groupName); - } - if (icon != null && icon.getIconWidth() <= 16 && icon.getIconHeight() <= 16) { - setIcon(IconUtil.toSize(icon, 16, 16)); - } - } - else if (isSetting(value)) { - String text = getSettingText((OptionDescription)value); - SimpleTextAttributes attrs = SimpleTextAttributes.REGULAR_ATTRIBUTES; - if (value instanceof Changeable && ((Changeable)value).hasChanged()) { - if (selected) { - attrs = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; - } else { - SimpleTextAttributes base = SimpleTextAttributes.LINK_BOLD_ATTRIBUTES; - attrs = base.derive(SimpleTextAttributes.STYLE_BOLD, base.getFgColor(), null, null); + if (icon != null && icon.getIconWidth() <= 16 && icon.getIconHeight() <= 16) { + setIcon(IconUtil.toSize(icon, 16, 16)); } } - append(text, attrs); - final String id = ((OptionDescription)value).getConfigurableId(); - final String name = myConfigurables.get(id); - if (name != null) { - setLocationString(name); + else if (isSetting(value)) { + String text = getSettingText((OptionDescription)value); + SimpleTextAttributes attrs = SimpleTextAttributes.REGULAR_ATTRIBUTES; + if (value instanceof Changeable && ((Changeable)value).hasChanged()) { + if (selected) { + attrs = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; + } + else { + SimpleTextAttributes base = SimpleTextAttributes.LINK_BOLD_ATTRIBUTES; + attrs = base.derive(SimpleTextAttributes.STYLE_BOLD, base.getFgColor(), null, null); + } + } + append(text, attrs); + final String id = ((OptionDescription)value).getConfigurableId(); + final String name = myConfigurables.get(id); + if (name != null) { + setLocationString(name); + } } - } - else if (value instanceof OptionsTopHitProvider) { - append("#" + ((OptionsTopHitProvider)value).getId()); - } - else { - ItemPresentation presentation = null; - if (value instanceof ItemPresentation) { - presentation = (ItemPresentation)value; + else if (value instanceof OptionsTopHitProvider) { + append("#" + ((OptionsTopHitProvider)value).getId()); } - else if (value instanceof NavigationItem) { - presentation = ((NavigationItem)value).getPresentation(); - } - if (presentation != null) { - final String text = presentation.getPresentableText(); - append(text == null ? value.toString() : text); - final String location = presentation.getLocationString(); - if (!StringUtil.isEmpty(location)) { - setLocationString(location); + else { + ItemPresentation presentation = null; + if (value instanceof ItemPresentation) { + presentation = (ItemPresentation)value; + } + else if (value instanceof NavigationItem) { + presentation = ((NavigationItem)value).getPresentation(); + } + if (presentation != null) { + final String text = presentation.getPresentableText(); + append(text == null ? value.toString() : text); + final String location = presentation.getLocationString(); + if (!StringUtil.isEmpty(location)) { + setLocationString(location); + } + Icon icon = presentation.getIcon(false); + if (icon != null) setIcon(icon); } - Icon icon = presentation.getIcon(false); - if (icon != null) setIcon(icon); } } - } - finally { - token.finish(); - } + }); } public void recalculateWidth() { From 7f799a8bb18f1ae336b88a74dc4f36896c491f00 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 18:22:39 +0300 Subject: [PATCH 10/17] EA-67215 - NPE: GeneralHighlightingPass$.value --- .../codeInsight/daemon/impl/GeneralHighlightingPass.java | 6 +++--- .../daemon/impl/InjectedGeneralHighlightingPass.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java index 41b1d4ccdde4..6a3a08b38b1d 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java @@ -66,9 +66,9 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass"); private static final String PRESENTABLE_NAME = DaemonBundle.message("pass.syntax"); private static final Key HAS_ERROR_ELEMENT = Key.create("HAS_ERROR_ELEMENT"); - static final Condition SHOULD_HIGHIGHT_FILTER = new Condition() { + static final Condition SHOULD_HIGHLIGHT_FILTER = new Condition() { @Override - public boolean value(PsiFile file) { + public boolean value(@NotNull PsiFile file) { return HighlightingLevelManager.getInstance(file.getProject()).shouldHighlight(file); } }; @@ -198,7 +198,7 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP List insideRanges = new ArrayList(); List outsideRanges = new ArrayList(); Divider.divideInsideAndOutside(getFile(), myRestrictRange.getStartOffset(), myRestrictRange.getEndOffset(), myPriorityRange, insideElements, insideRanges, outsideElements, - outsideRanges, false, SHOULD_HIGHIGHT_FILTER); + outsideRanges, false, SHOULD_HIGHLIGHT_FILTER); // put file element always in outsideElements if (!insideElements.isEmpty() && insideElements.get(insideElements.size()-1) instanceof PsiFile) { PsiElement file = insideElements.remove(insideElements.size() - 1); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java index e9d28c1fd51b..be7924e32838 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java @@ -82,7 +82,7 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp List outsideRanges = new ArrayList(); //TODO: this thing is just called TWICE with same arguments eating CPU on huge files :( Divider.divideInsideAndOutside(myFile, myRestrictRange.getStartOffset(), myRestrictRange.getEndOffset(), myPriorityRange, inside, insideRanges, outside, - outsideRanges, false, SHOULD_HIGHIGHT_FILTER); + outsideRanges, false, SHOULD_HIGHLIGHT_FILTER); // all infos for the "injected fragment for the host which is inside" are indeed inside From ed9d4242789e695cf8b4cf33afda6a47b46cb32a Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 18:31:53 +0300 Subject: [PATCH 11/17] diagnostics for EA-66858 - assert: UnitBitSet.pack --- .../spellchecker/compress/Alphabet.java | 17 ++++++++---- .../spellchecker/compress/UnitBitSet.java | 27 +++++++++---------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/spellchecker/src/com/intellij/spellchecker/compress/Alphabet.java b/spellchecker/src/com/intellij/spellchecker/compress/Alphabet.java index 0b322e0e86d3..c63c242db6b7 100644 --- a/spellchecker/src/com/intellij/spellchecker/compress/Alphabet.java +++ b/spellchecker/src/com/intellij/spellchecker/compress/Alphabet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,12 +18,14 @@ package com.intellij.spellchecker.compress; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; +import java.util.Arrays; + public final class Alphabet { private final char[] letters; private int lastIndexUsed; private static final int MAX_INDEX = UnitBitSet.MAX_UNIT_VALUE; - public char getLetter(int position) { + char getLetter(int position) { return letters[position]; } @@ -40,7 +42,7 @@ public final class Alphabet { @param forceAdd - if set to true - letter will be added to the alphabet if not present yet @return index of the letter or -1 if letter was not found and could not be added (due to forceAdd property value) */ - public int getNextIndex(int startFrom, char letter, boolean forceAdd) { + private int getNextIndex(int startFrom, char letter, boolean forceAdd) { for (int i = startFrom; i <= lastIndexUsed; i++) { if (i == letters.length) return -1; if (letters[i] != 0 && letters[i] == letter) { @@ -53,7 +55,7 @@ public final class Alphabet { return add(letter); } - public int getLastIndexUsed() { + int getLastIndexUsed() { return lastIndexUsed; } @@ -69,7 +71,7 @@ public final class Alphabet { this(MAX_INDEX); } - Alphabet(int maxIndex) { + private Alphabet(int maxIndex) { assert maxIndex <= MAX_INDEX : "alphabet is too long"; letters = new char[maxIndex]; } @@ -83,4 +85,9 @@ public final class Alphabet { add(alphabet.charAt(i)); } } + + @Override + public String toString() { + return "Letters[" + lastIndexUsed + "]: '" + Arrays.toString(Arrays.copyOf(letters, lastIndexUsed))+"'"; + } } diff --git a/spellchecker/src/com/intellij/spellchecker/compress/UnitBitSet.java b/spellchecker/src/com/intellij/spellchecker/compress/UnitBitSet.java index 01d427413943..ffe8e9537497 100644 --- a/spellchecker/src/com/intellij/spellchecker/compress/UnitBitSet.java +++ b/spellchecker/src/com/intellij/spellchecker/compress/UnitBitSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,25 +19,25 @@ import org.jetbrains.annotations.NotNull; import java.util.Arrays; -public class UnitBitSet { - public static final int MAX_CHARS_IN_WORD = 64; - public static final int MAX_UNIT_VALUE = 255; +class UnitBitSet { + static final int MAX_CHARS_IN_WORD = 64; + static final int MAX_UNIT_VALUE = 255; final byte[] b; private final Alphabet alpha; - public UnitBitSet(@NotNull byte[] indices, @NotNull Alphabet alphabet) { + UnitBitSet(@NotNull byte[] indices, @NotNull Alphabet alphabet) { b = indices; alpha = alphabet; } - public int getUnitValue(int number) { + int getUnitValue(int number) { final int r = b[number] & 0xFF; assert r >= 0 && r <= MAX_UNIT_VALUE : "invalid unit value"; return r; } - public void setUnitValue(int number, int value) { + void setUnitValue(int number, int value) { assert value >= 0 : "unit value is negative" + value; assert value <= MAX_UNIT_VALUE : "unit value is too big"; b[number] = (byte)value; @@ -45,8 +45,7 @@ public class UnitBitSet { @Override public boolean equals(Object obj) { - if (!(obj instanceof UnitBitSet)) return false; - return Arrays.equals(b, ((UnitBitSet)obj).b); + return obj instanceof UnitBitSet && Arrays.equals(b, ((UnitBitSet)obj).b); } @Override @@ -61,7 +60,7 @@ public class UnitBitSet { @NotNull public byte[] pack() { int meaningfulBits = 32 - Integer.numberOfLeadingZeros(alpha.getLastIndexUsed()); - assert meaningfulBits <= 8 && meaningfulBits >= 1 : meaningfulBits + ": "+alpha.getLastIndexUsed(); + assert meaningfulBits <= 8 && meaningfulBits >= 1 : meaningfulBits + ": "+alpha; byte[] result = new byte[(b.length * meaningfulBits + 7) / 8]; int byteNumber = 0; @@ -87,7 +86,7 @@ public class UnitBitSet { @NotNull public static String decode(@NotNull byte[] packed, @NotNull Alphabet alphabet) { int meaningfulBits = 32 - Integer.numberOfLeadingZeros(alphabet.getLastIndexUsed()); - assert meaningfulBits <= 8; + assert meaningfulBits <= 8 : alphabet; StringBuilder result = new StringBuilder(packed.length * 8 / meaningfulBits); @@ -105,7 +104,7 @@ public class UnitBitSet { curByte >>>= meaningfulBits; bitOffset += meaningfulBits; - assert bitOffset <= 8; + assert bitOffset <= 8 : alphabet; if (bitOffset + meaningfulBits > 8) { if (++byteIndex == packed.length) break; int leftOverBits = 8 - bitOffset; @@ -116,9 +115,9 @@ public class UnitBitSet { return result.toString(); } - public static int getFirstLetterIndex(byte firstPackedByte, @NotNull Alphabet alphabet) { + static int getFirstLetterIndex(byte firstPackedByte, @NotNull Alphabet alphabet) { int meaningfulBits = 32 - Integer.numberOfLeadingZeros(alphabet.getLastIndexUsed()); - assert meaningfulBits <= 8; + assert meaningfulBits <= 8 : alphabet; int index = firstPackedByte & ((1 << meaningfulBits) - 1); return index; From 28d99fb494f4cd72e87288bf5f47b6834bb8ece1 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 18:38:13 +0300 Subject: [PATCH 12/17] better diagnostics for EA-64802 - ISE: GlobalSearchScope$UnionScope. --- .../src/com/intellij/psi/search/GlobalSearchScope.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java b/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java index 5cfe992294b3..64f4da0c8a2e 100644 --- a/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java +++ b/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java @@ -157,7 +157,7 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw @NonNls @Override public String toString() { - return "UnionToLocal: (" + GlobalSearchScope.this.toString() + ", " + scope + ")"; + return "UnionToLocal: (" + GlobalSearchScope.this + ", " + scope + ")"; } }; } @@ -446,7 +446,7 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw }); myNestingLevel = 1 + nested[0]; if (myNestingLevel > 1000) { - throw new IllegalStateException("Too many scopes combined: " + myNestingLevel + StringUtil.first(toString(), 500, true)); + throw new IllegalStateException("Too many scopes combined: " + myNestingLevel + StringUtil.last(toString(), 500, true)); } } From 7765d344e4d1f10baf673e6e4b580f29af470f83 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 19:57:40 +0300 Subject: [PATCH 13/17] constant introduced for light project name --- .../src/com/intellij/openapi/project/impl/ProjectImpl.java | 4 +++- .../src/com/intellij/testFramework/LightPlatformTestCase.java | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index be46cb49a2c1..c876bb9694ec 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -66,6 +66,8 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project public static final String NAME_FILE = ".name"; public static final Key CREATION_TIME = Key.create("ProjectImpl.CREATION_TIME"); public static final Key CREATION_TRACE = Key.create("ProjectImpl.CREATION_TRACE"); + @TestOnly + public static final String LIGHT_PROJECT_NAME = "light_temp"; private ProjectManager myProjectManager; private MyProjectManagerListener myProjectManagerListener; @@ -103,7 +105,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project } // light project may be changed later during test, so we need to remember its initial state - myLight = ApplicationManager.getApplication().isUnitTestMode() && filePath.contains("light_temp_"); + myLight = ApplicationManager.getApplication().isUnitTestMode() && filePath.contains(LIGHT_PROJECT_NAME); } @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 1b558dd46b99..83963e72907a 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -61,6 +61,7 @@ import com.intellij.openapi.project.ModuleAdapter; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ex.ProjectManagerEx; +import com.intellij.openapi.project.impl.ProjectImpl; import com.intellij.openapi.project.impl.ProjectManagerImpl; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootManager; @@ -241,7 +242,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da token.finish(); } - final File projectFile = FileUtil.createTempFile("light_temp_", ProjectFileType.DOT_DEFAULT_EXTENSION); + final File projectFile = FileUtil.createTempFile(ProjectImpl.LIGHT_PROJECT_NAME, ProjectFileType.DOT_DEFAULT_EXTENSION); LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectFile); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); From fd339313dcf2503ced7ba33004fe215770418d68 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 21 Oct 2015 20:00:18 +0300 Subject: [PATCH 14/17] make temporary names more nice-looking, remove project files cached in VFS from the previous tests --- .../unusedLibrary/simple/expected.xml | 2 +- .../testFramework/PlatformTestCase.java | 7 +- .../testFramework/UsefulTestCase.java | 2 +- .../intellij/openapi/util/io/FileUtilRt.java | 65 +++++++------------ 4 files changed, 32 insertions(+), 44 deletions(-) diff --git a/java/java-tests/testData/inspection/unusedLibrary/simple/expected.xml b/java/java-tests/testData/inspection/unusedLibrary/simple/expected.xml index 8184735d55cf..9cd23b0df42b 100644 --- a/java/java-tests/testData/inspection/unusedLibrary/simple/expected.xml +++ b/java/java-tests/testData/inspection/unusedLibrary/simple/expected.xml @@ -1,7 +1,7 @@ - testSimple_0.iml + testSimple.iml Unused library Unused library 'JUnit' diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index d1e5c6663726..afb7063bf09c 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -110,7 +110,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro protected boolean myAssertionsInTestDetected; protected static final Logger LOG = Logger.getInstance("#com.intellij.testFramework.PlatformTestCase"); public static Thread ourTestThread; - private static TestCase ourTestCase = null; + private static TestCase ourTestCase; public static final long DEFAULT_TEST_TIME = 300L; public static long ourTestTime = DEFAULT_TEST_TIME; private EditorListenerTracker myEditorListenerTracker; @@ -191,6 +191,9 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro @Override protected void setUp() throws Exception { super.setUp(); + File tempDir = new File(FileUtilRt.getTempDirectory()); + myFilesToDelete.add(tempDir); + if (ourTestCase != null) { String message = "Previous test " + ourTestCase + " hasn't called tearDown(). Probably overridden without super call."; ourTestCase = null; @@ -307,7 +310,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } protected File getIprFile() throws IOException { - File tempFile = FileUtil.createTempFile(getName() + "_", ProjectFileType.DOT_DEFAULT_EXTENSION); + File tempFile = FileUtil.createTempFile(getName(), ProjectFileType.DOT_DEFAULT_EXTENSION); myFilesToDelete.add(tempFile); return tempFile; } diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index fcc8bee14fb6..71718080f774 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -139,7 +139,7 @@ public abstract class UsefulTestCase extends TestCase { String testName = FileUtil.sanitizeFileName(getTestName(true)); if (StringUtil.isEmptyOrSpaces(testName)) testName = ""; testName = new File(testName).getName(); // in case the test name contains file separators - myTempDir = FileUtil.toSystemDependentName(ORIGINAL_TEMP_DIR + "/" + TEMP_DIR_MARKER + testName + "_"+ RNG.nextInt(1000)); + myTempDir = new File(ORIGINAL_TEMP_DIR, TEMP_DIR_MARKER + testName).getPath(); FileUtil.resetCanonicalTempPathCache(myTempDir); } ApplicationInfoImpl.setInPerformanceTest(isPerformanceTest()); diff --git a/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java index 3c1cfabb1acb..e9aac8b47c50 100644 --- a/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java +++ b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java @@ -315,7 +315,7 @@ public class FileUtilRt { } private static class FilesToDeleteHolder { - public static final Queue ourFilesToDelete = createFilesToDelete(); + private static final Queue ourFilesToDelete = createFilesToDelete(); private static Queue createFilesToDelete() { final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); @@ -387,62 +387,47 @@ public class FileUtilRt { prefix = (prefix + "___").substring(0, 3); } if (suffix == null) { - suffix = ".tmp"; + suffix = ""; } + // normalize and use only the file name from the prefix + prefix = new File(prefix).getName(); int exceptionsCount = 0; + int i = 0; while (true) { try { - // If there was an IOException, there's no reason to do sequential search - fallback to random - final File temp = createTemp(prefix, suffix, dir, isDirectory, exceptionsCount > 0); - return normalizeFile(temp); + File f = calcName(dir, prefix, suffix, i); + + boolean success = isDirectory ? f.mkdir() : f.createNewFile(); + if (!success) { + throw new IOException("Unable to create temporary file " + f); + } + + return normalizeFile(f); } catch (IOException e) { // Win32 createFileExclusively access denied if (++exceptionsCount >= 100) { throw e; } } + i++; // for some reason the file1 can't be created (previous file1 was deleted but got locked by anti-virus?). try file2. + if (i > 2) { + i = 2 + (int)(System.nanoTime() % 998); // generate random suffix if too many failures + } } } @NotNull - private static File createTemp(@NotNull String prefix, - @NotNull String suffix, - @NotNull File directory, - boolean isDirectory, - boolean randomName) throws IOException { - // Fallback to the original File.createTempFile - if (randomName) { - @SuppressWarnings("SSBasedInspection") - File res = File.createTempFile(prefix, suffix, directory); - if (isDirectory) { - if (!res.delete() || !res.mkdir()) { - throw new IOException("Cannot create directory: " + res); - } - } - return res; + private static File calcName(@NotNull File dir, @NotNull String prefix, @NotNull String suffix, int i) throws IOException { + prefix += i == 0 ? "" : i; + if (prefix.endsWith(".") && suffix.startsWith(".")) { + prefix = prefix.substring(0, prefix.length() - 1); } - - // normalize and use only the file name from the prefix - prefix = new File(prefix).getName(); - - File f; - int i = 0; - do { - String name = prefix + i + suffix; - f = new File(directory, name); - if (!name.equals(f.getName())) { - throw new IOException("Unable to create temporary file " + f + " for name " + name); - } - i++; + String name = prefix + suffix; + File f = new File(dir, name); + if (!name.equals(f.getName())) { + throw new IOException("Unable to create temporary file " + f + " for name " + name); } - while (f.exists()); - - boolean success = isDirectory ? f.mkdir() : f.createNewFile(); - if (!success) { - throw new IOException("Unable to create temporary file " + f); - } - return f; } From 7ddb2d933c5aa018c11e94497da6e1cbb672cc3d Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Thu, 22 Oct 2015 14:34:07 +0300 Subject: [PATCH 15/17] test framework: prevent test failure on case-sensitive file systems: fast fail if the requested and real paths are not case-sensitive equal --- .../com/intellij/codeInsight/CodeInsightTestCase.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java index 28efa2baae3f..f611ae7cbf80 100644 --- a/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java @@ -40,6 +40,7 @@ import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; @@ -544,8 +545,16 @@ public abstract class CodeInsightTestCase extends PsiTestCase { String fullPath = getTestDataPath() + filePath; allowRootAccess(fullPath); - final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/')); + String vfsPath = FileUtil.toSystemIndependentName(fullPath); + VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(vfsPath); assertNotNull("file " + fullPath + " not found", vFile); + String realVfsPath = vFile.getPath(); + if (!SystemInfo.isFileSystemCaseSensitive && !vfsPath.equals(realVfsPath) && + vfsPath.equalsIgnoreCase(realVfsPath)) { + fail("Please correct case-sensitivity of path to prevent test failure on case-sensitive file systems:\n" + + " path " + vfsPath + "\n" + + "real path " + realVfsPath); + } return vFile; } From e903cb0e4c7a3665fbb92b7f8ab22d20a6ecc353 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 22 Oct 2015 14:50:04 +0300 Subject: [PATCH 16/17] guava type migration: added test for complex structure --- .../GuavaFluentIterableConversionRule.java | 3 +- .../inspections/GuavaInspectionTest.java | 8 +++++ .../guava/fluentIterableAndOptional.java | 25 +++++++++++++++ .../fluentIterableAndOptional_after.java | 25 +++++++++++++++ .../fluentIterableMigrationInInheritance.java | 31 +++++++++++++++++++ ...tIterableMigrationInInheritance_after.java | 24 ++++++++++++++ 6 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 java/typeMigration/testData/inspections/guava/fluentIterableAndOptional.java create mode 100644 java/typeMigration/testData/inspections/guava/fluentIterableAndOptional_after.java create mode 100644 java/typeMigration/testData/inspections/guava/fluentIterableMigrationInInheritance.java create mode 100644 java/typeMigration/testData/inspections/guava/fluentIterableMigrationInInheritance_after.java diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java index a90f7639be1a..7593fc57f3ee 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java @@ -92,13 +92,12 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu DESCRIPTORS_MAP.put("isEmpty", new TypeConversionDescriptorFactory("$q$.isEmpty()", "$q$.findAny().isPresent()", false)); DESCRIPTORS_MAP.put("skip", new TypeConversionDescriptorFactory("$q$.skip($p$)", "$q$.skip($p$)", false, true, true)); DESCRIPTORS_MAP.put("limit", new TypeConversionDescriptorFactory("$q$.limit($p$)", "$q$.limit($p$)", false, true, true)); - DESCRIPTORS_MAP.put("first", new TypeConversionDescriptorFactory("$q$.first()", "$q$.findFirst()", false)); + DESCRIPTORS_MAP.put("first", new TypeConversionDescriptorFactory("$q$.first()", "$q$.findFirst()", false, true, false)); DESCRIPTORS_MAP.put("transform", new TypeConversionDescriptorFactory("$q$.transform($params$)", "$q$.map($params$)", true, true, true)); DESCRIPTORS_MAP.put("allMatch", new TypeConversionDescriptorFactory("$it$.allMatch($c$)", "$it$." + StreamApiConstants.ALL_MATCH + "($c$)", true)); DESCRIPTORS_MAP.put("anyMatch", new TypeConversionDescriptorFactory("$it$.anyMatch($c$)", "$it$." + StreamApiConstants.ANY_MATCH + "($c$)", true)); - DESCRIPTORS_MAP.put("first", new TypeConversionDescriptorFactory("$it$.first()", "$it$." + StreamApiConstants.FIND_FIRST + "()", false)); DESCRIPTORS_MAP.put("firstMatch", new TypeConversionDescriptorFactory("$it$.firstMatch($p$)", "$it$.filter($p$).findFirst()", true, true, false)); DESCRIPTORS_MAP.put("size", new TypeConversionDescriptorFactory("$it$.size()", "(int) $it$.count()", false)); diff --git a/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java b/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java index 4fa31f9ad75f..a864df425701 100644 --- a/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java +++ b/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java @@ -162,6 +162,14 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase { doTest(); } + public void testFluentIterableMigrationInInheritance() { + doTest(); + } + + public void testFluentIterableAndOptional() { + doTest(); + } + private void doTestNoQuickFixes(final Class... quickFixesClasses) { myFixture.configureByFile(getTestName(true) + ".java"); myFixture.enableInspections(new GuavaInspection()); diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional.java b/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional.java new file mode 100644 index 000000000000..e942a7c9e815 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional.java @@ -0,0 +1,25 @@ +import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; + +import java.util.ArrayList; + +public class Main18 { + + class A { + private String i = "12"; + + Optional getOpt() { + return Optional.fromNullable(i); + } + } + + class B { + FluentIterable getFIterable() { + return FluentIterable.from(new ArrayList()).filter(String.class); + } + } + + void m(A a, B b) { + String sss = b.getFIterable().transform(s -> s).first().or(a.getOpt()).get(); + } +} diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional_after.java b/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional_after.java new file mode 100644 index 000000000000..d717ca06ec09 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional_after.java @@ -0,0 +1,25 @@ +import com.google.common.base.Optional; + +import java.util.ArrayList; +import java.util.stream.Stream; + +public class Main18 { + + class A { + private String i = "12"; + + Optional getOpt() { + return Optional.fromNullable(i); + } + } + + class B { + Stream getFIterable() { + return new ArrayList().stream().filter(String.class::isInstance); + } + } + + void m(A a, B b) { + String sss = java.util.Optional.ofNullable(b.getFIterable().map(s -> s).findFirst().orElseGet(a.getOpt()::get)).get(); + } +} diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableMigrationInInheritance.java b/java/typeMigration/testData/inspections/guava/fluentIterableMigrationInInheritance.java new file mode 100644 index 000000000000..f943cae23623 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableMigrationInInheritance.java @@ -0,0 +1,31 @@ +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; + +import java.util.ArrayList; + +public class Main17 { + + interface A { + FluentIterable getIterable(); + } + + class B implements A { + @Override + public FluentIterable getIterable() { + return FluentIterable.from(new ArrayList()).transform(new Function() { + @Override + public String apply(String s) { + return s.intern(); + } + }); + } + } + + static void m(A a) { + int s = a.getIterable().transform(s1 -> s1).size(); + } + + static void m2(B b) { + int s = b.getIterable().size(); + } +} diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableMigrationInInheritance_after.java b/java/typeMigration/testData/inspections/guava/fluentIterableMigrationInInheritance_after.java new file mode 100644 index 000000000000..3193f3230d04 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableMigrationInInheritance_after.java @@ -0,0 +1,24 @@ +import java.util.ArrayList; +import java.util.stream.Stream; + +public class Main17 { + + interface A { + Stream getIterable(); + } + + class B implements A { + @Override + public Stream getIterable() { + return new ArrayList().stream().map(s -> s.intern()); + } + } + + static void m(A a) { + int s = (int) a.getIterable().map(s1 -> s1).count(); + } + + static void m2(B b) { + int s = (int) b.getIterable().count(); + } +} From a83f3dd9c53fd2fad58007485ba969836d8794df Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 22 Oct 2015 13:47:31 +0200 Subject: [PATCH 17/17] Restore cwd if it was changed during test execution (PY-17136) --- python/helpers/coverage_runner/run_coverage.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/helpers/coverage_runner/run_coverage.py b/python/helpers/coverage_runner/run_coverage.py index c9892d815929..f637d6e8d42c 100644 --- a/python/helpers/coverage_runner/run_coverage.py +++ b/python/helpers/coverage_runner/run_coverage.py @@ -40,6 +40,8 @@ for arg in sys.argv: argv.append(arg) sys.argv = argv +cwd = os.getcwd() main() if run_cov: + os.chdir(cwd) main(["xml", "-o", coverage_file + ".xml", "--ignore-errors"]) \ No newline at end of file