<component name="libraryTable">
<library name="Gradle">
<CLASSES>
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-tooling-api-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-core-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-messaging-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-model-core-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-model-groovy-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-wrapper-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-base-services-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-base-services-groovy-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-native-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-resources-2.13.jar!/" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-cli-2.13.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-tooling-api-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-core-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-messaging-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-model-core-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-model-groovy-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-wrapper-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-base-services-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-base-services-groovy-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-process-services-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-native-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-resources-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-cli-2.14.1.jar!/" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-logging-2.14.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/tooling-api/src/main/java" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/core/src/main/groovy" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/model-core/src/main/java" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/model-groovy/src/main/java" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/messaging/src/main/java" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/wrapper/src/main/java" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/base-services/src/main/java" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/base-services-groovy/src/main/groovy" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/native/src/main/java" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/resources/src/main/java" />
- <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.13-src.zip!/gradle-2.13/subprojects/cli/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/tooling-api/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/core/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/model-core/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/model-groovy/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/messaging/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/wrapper/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/base-services/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/base-services-groovy/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/process-services/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/native/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/resources/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/cli/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/plugins/gradle/lib/gradle-2.14.1-src.zip!/gradle-2.14.1/subprojects/logging/src/main/java" />
</SOURCES>
</library>
</component>
\ No newline at end of file
new LibraryLicense(name: "Gherkin", libraryName: "Gherkin", version: "2.12.2", license: "MIT",
licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://github.com/cucumber/gherkin"),
new LibraryLicense(name: "Google Feedback", libraryName: "GoogleFeedback.jar", version: "", license: "TBD"),
- new LibraryLicense(name: "gradle-tooling-api-2.13.jar", version: "2.13", license: "Apache 2.0", url: "http://gradle.org/",
+ new LibraryLicense(name: "gradle-tooling-api-2.14.1.jar", version: "2.14.1", license: "Apache 2.0", url: "http://gradle.org/",
licenseUrl: "http://gradle.org/license"),
- new LibraryLicense(name: "Gradle", version: "2.13", license: "Apache 2.0", url: "http://gradle.org/",
+ new LibraryLicense(name: "Gradle", version: "2.14.1", license: "Apache 2.0", url: "http://gradle.org/",
licenseUrl: "http://gradle.org/license"),
new LibraryLicense(name: "GradleGuava", version: "14.0.1", license: "Apache 2.0", url: "http://code.google.com/p/guava-libraries/",
licenseUrl: "http://apache.org/licenses/LICENSE-2.0"),
echo "Unsupported platform, JRE download skipped"
return
}
+ if (jreArchitecture == "disable") {
+ echo "JRE update disabled"
+ return
+ }
if (!(jreArchitecture == "64" || jreArchitecture == "32" && platform == "win")) {
echo "Acceptable architecture (32 or 64 bit) is not defined, JRE download skipped"
return
--- /dev/null
+<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+ <title>ImagesFileType</title>
+ <g>
+ <polygon points="6 0 2 4 6 4 6 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
+ <path d="M7,0V5H2V15H13V0H7Zm5,14H3V6h9v8Z" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
+ <path d="M11,13H4V11s2.06361-1.89568,3-1a9.5647,9.5647,0,0,0,4,2v1Z" fill="#62b543" opacity="0.8"/>
+ <path d="M4,7v3S6.06348,8.10449,7,9a9.56218,9.56218,0,0,0,4,2V7H4ZM9.5,9A0.5,0.5,0,1,1,10,8.5,0.49987,0.49987,0,0,1,9.5,9Z" fill="#40b6e0" opacity="0.8"/>
+ </g>
+</svg>
--- /dev/null
+<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
+ <title>ImagesFileType@2x</title>
+ <g>
+ <polygon points="12 0 4 8 12 8 12 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
+ <path d="M14,0V10H4V30H26V0H14ZM24,28H6V12H24V28Z" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
+ <path d="M22,26H8V22s4.12722-3.79136,6-2c3.06667,2.93333,8,4,8,4v2Z" fill="#62b543" opacity="0.8"/>
+ <path d="M8,14v6s4.127-3.791,6-2c3.06641,2.93359,8,4,8,4V14H8Zm11,4a1,1,0,1,1,1-1A0.99974,0.99974,0,0,1,19,18Z" fill="#40b6e0" opacity="0.8"/>
+ </g>
+</svg>
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompileStatusNotification;
import com.intellij.openapi.compiler.CompilerManager;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
* @since 5/11/2016
*/
public class InternalProjectTaskRunner extends ProjectTaskRunner {
+ private static final Logger LOG = Logger.getInstance(InternalProjectTaskRunner.class);
+
@Override
public void run(@NotNull Project project,
@NotNull ProjectTaskContext context,
if (!ContainerUtil.isEmpty(buildTasks)) {
- List<Module> toMake = new SmartList<>();
- List<Module> toCompile = new SmartList<>();
+ List<Module> modules = new SmartList<>();
+
+ Boolean isIncrementalBuild = null;
+ Boolean includeDependentModules = null;
+ Boolean includeRuntimeDependencies = null;
for (ProjectTask buildProjectTask : buildTasks) {
ModuleBuildTask moduleBuildTask = (ModuleBuildTask)buildProjectTask;
-
- if (moduleBuildTask.isIncrementalBuild()) {
- toMake.add(moduleBuildTask.getModule());
+ assertModuleBuildSettings(moduleBuildTask, isIncrementalBuild, includeDependentModules, includeRuntimeDependencies);
+ modules.add(moduleBuildTask.getModule());
+ if (!moduleBuildTask.isIncrementalBuild()) {
+ isIncrementalBuild = false;
}
- else {
- toCompile.add(moduleBuildTask.getModule());
+ if (moduleBuildTask.isIncludeDependentModules()) {
+ includeDependentModules = true;
+ }
+ if (moduleBuildTask.isIncludeRuntimeDependencies()) {
+ includeRuntimeDependencies = true;
}
}
CompilerManager compilerManager = CompilerManager.getInstance(project);
- if (!toMake.isEmpty()) {
- CompileScope scope = createScope(project, compilerManager, context, toMake);
- // TODO handle multiple notifications
+ CompileScope scope = createScope(
+ compilerManager, context, modules, includeDependentModules != null, includeRuntimeDependencies != null);
+ if (isIncrementalBuild == null) {
compilerManager.make(scope, compileNotification);
}
- if (!toCompile.isEmpty()) {
- CompileScope scope = createScope(project, compilerManager, context, toCompile);
- // TODO handle multiple notifications
+ else {
compilerManager.compile(scope, compileNotification);
}
}
}
+ private static void assertModuleBuildSettings(ModuleBuildTask moduleBuildTask,
+ Boolean isIncrementalBuild,
+ Boolean includeDependentModules,
+ Boolean includeRuntimeDependencies) {
+ if (isIncrementalBuild != null && moduleBuildTask.isIncrementalBuild()) {
+ LOG.warn("Incremental build setting for the module '" + moduleBuildTask.getModule().getName() + "' will be ignored");
+ }
+ if (includeDependentModules != null && !moduleBuildTask.isIncludeDependentModules()) {
+ LOG.warn("'Module '" + moduleBuildTask.getModule().getName() + "' will be built along with dependent modules");
+ }
+ if (includeRuntimeDependencies != null && !moduleBuildTask.isIncludeRuntimeDependencies()) {
+ LOG.warn("'Module '" + moduleBuildTask.getModule().getName() + "' will be built along with runtime dependencies");
+ }
+ }
- private static CompileScope createScope(Project project,
- CompilerManager compilerManager,
+ private static CompileScope createScope(CompilerManager compilerManager,
ProjectTaskContext context,
- Collection<Module> modules) {
- CompileScope scope = compilerManager.createModuleGroupCompileScope(project, modules.toArray(new Module[modules.size()]), true);
+ Collection<Module> modules,
+ boolean includeDependentModules,
+ boolean includeRuntimeDependencies) {
+ CompileScope scope = compilerManager.createModulesCompileScope(
+ modules.toArray(new Module[modules.size()]), includeDependentModules, includeRuntimeDependencies);
RunConfiguration configuration = context.getRunConfiguration();
if (configuration != null) {
scope.putUserData(CompilerManager.RUN_CONFIGURATION_KEY, configuration);
public class ModuleBuildTaskImpl extends AbstractBuildTask implements ModuleBuildTask {
@NotNull
private final Module myModule;
+ private final boolean myIncludeDependentModules;
+ private final boolean myIncludeRuntimeDependencies;
public ModuleBuildTaskImpl(@NotNull Module module, boolean isIncrementalBuild) {
+ this(module, isIncrementalBuild, false, false);
+ }
+
+ public ModuleBuildTaskImpl(@NotNull Module module,
+ boolean isIncrementalBuild,
+ boolean includeDependentModules,
+ boolean includeRuntimeDependencies) {
super(isIncrementalBuild);
myModule = module;
+ myIncludeDependentModules = includeDependentModules;
+ myIncludeRuntimeDependencies = includeRuntimeDependencies;
}
@NotNull
return myModule;
}
+ @Override
+ public boolean isIncludeDependentModules() {
+ return myIncludeDependentModules;
+ }
+
+ @Override
+ public boolean isIncludeRuntimeDependencies() {
+ return myIncludeRuntimeDependencies;
+ }
+
@NotNull
@Override
public String getPresentableName() {
import com.intellij.task.*;
import com.intellij.util.Consumer;
import com.intellij.util.SmartList;
+import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Override
public void build(@NotNull Module[] modules, @Nullable ProjectTaskNotification callback) {
- run(createModulesBuildTask(true, modules), callback);
+ run(createModulesBuildTask(modules, true, true, false), callback);
}
@Override
public void rebuild(@NotNull Module[] modules, @Nullable ProjectTaskNotification callback) {
- run(createModulesBuildTask(false, modules), callback);
+ run(createModulesBuildTask(modules, false, false, false), callback);
}
@Override
@Override
public ProjectTask createAllModulesBuildTask(boolean isIncrementalBuild, Project project) {
- return createModulesBuildTask(isIncrementalBuild, ModuleManager.getInstance(project).getModules());
+ return createModulesBuildTask(ModuleManager.getInstance(project).getModules(), isIncrementalBuild, false, false);
}
@Override
- public ProjectTask createModulesBuildTask(boolean isIncrementalBuild, Module... modules) {
+ public ProjectTask createModulesBuildTask(Module module,
+ boolean isIncrementalBuild,
+ boolean includeDependentModules,
+ boolean includeRuntimeDependencies) {
+ return createModulesBuildTask(ContainerUtil.ar(module), isIncrementalBuild, includeDependentModules, includeRuntimeDependencies);
+ }
+
+ @Override
+ public ProjectTask createModulesBuildTask(Module[] modules,
+ boolean isIncrementalBuild,
+ boolean includeDependentModules,
+ boolean includeRuntimeDependencies) {
return modules.length == 1
- ? new ModuleBuildTaskImpl(modules[0], isIncrementalBuild)
- : new ProjectTaskList(map(list(modules), module -> new ModuleBuildTaskImpl(module, isIncrementalBuild)));
+ ? new ModuleBuildTaskImpl(modules[0], isIncrementalBuild, includeDependentModules, includeRuntimeDependencies)
+ : new ProjectTaskList(map(list(modules), module ->
+ new ModuleBuildTaskImpl(module, isIncrementalBuild, includeDependentModules, includeRuntimeDependencies)));
}
@Override
public interface ModuleBuildTask extends BuildTask {
@NotNull
Module getModule();
+
+ boolean isIncludeDependentModules();
+
+ boolean isIncludeRuntimeDependencies();
}
public abstract ProjectTask createAllModulesBuildTask(boolean isIncrementalBuild, Project project);
- public abstract ProjectTask createModulesBuildTask(boolean isIncrementalBuild, Module... modules);
+ public abstract ProjectTask createModulesBuildTask(Module module,
+ boolean isIncrementalBuild,
+ boolean includeDependentModules,
+ boolean includeRuntimeDependencies);
+
+ public abstract ProjectTask createModulesBuildTask(Module[] modules,
+ boolean isIncrementalBuild,
+ boolean includeDependentModules,
+ boolean includeRuntimeDependencies);
public abstract ProjectTask createArtifactsBuildTask(boolean isIncrementalBuild, Artifact... artifacts);
runConfiguration.getClass().getName());
}
}
- projectTask = projectTaskManager.createModulesBuildTask(true, modules);
+ projectTask = projectTaskManager.createModulesBuildTask(modules, true, true, true);
}
else {
projectTask = projectTaskManager.createAllModulesBuildTask(true, myProject);
private Set<RefElement> myInTypeReferences;
private Set<RefElement> myInstanceReferences;
private List<RefJavaElement> myClassExporters;
+ private RefModule myRefModule;
RefClassImpl(PsiClass psiClass, RefManager manager) {
super(psiClass, manager);
+ myRefModule = manager.getRefModule(ModuleUtilCore.findModuleForPsiElement(psiClass));
}
@Override
return (PsiClass)super.getElement();
}
+ @Nullable
+ @Override
+ public RefModule getModule() {
+ return myRefModule;
+ }
+
private static boolean isSelfInheritor(PsiClass psiClass, ArrayList<PsiClass> visited) {
if (visited.contains(psiClass)) return true;
public class RefImplicitConstructorImpl extends RefMethodImpl implements RefImplicitConstructor {
+ private final RefClass myOwnerClass;
RefImplicitConstructorImpl(@NotNull RefClass ownerClass) {
super(InspectionsBundle.message("inspection.reference.implicit.constructor.name", ownerClass.getName()), ownerClass);
+ myOwnerClass = ownerClass;
}
@Override
private RefParameter[] myParameters;
private String myReturnValueTemplate;
- protected final RefClass myOwnerClass;
RefMethodImpl(@NotNull RefClass ownerClass, PsiMethod method, RefManager manager) {
super(method, manager);
((RefClassImpl)ownerClass).add(this);
-
- myOwnerClass = ownerClass;
}
// To be used only from RefImplicitConstructor.
protected RefMethodImpl(@NotNull String name, @NotNull RefClass ownerClass) {
super(name, ownerClass);
- myOwnerClass = ownerClass;
((RefClassImpl)ownerClass).add(this);
- addOutReference(getOwnerClass());
- ((RefClassImpl)getOwnerClass()).addInReference(this);
+ addOutReference(ownerClass);
+ ((RefClassImpl)ownerClass).addInReference(this);
setConstructor(true);
}
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
+import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
PsiParameter parameter,
String value) {
final String name = parameter.getName();
- return manager.createProblemDescriptor(parameter,
+ return manager.createProblemDescriptor(ObjectUtils.notNull(parameter.getNameIdentifier(), parameter),
InspectionsBundle.message("inspection.same.parameter.problem.descriptor",
"<code>" + name + "</code>",
"<code>" + value + "</code>"),
final PsiType type1 = ((PsiNewExpression)pattern).getType();
final PsiType type2 = ((PsiNewExpression)candidate).getType();
if (type1 == null || type2 == null) return false;
- final PsiJavaCodeReferenceElement classReference1 = ((PsiNewExpression)pattern).getClassReference();
- final PsiJavaCodeReferenceElement classReference2 = ((PsiNewExpression)candidate).getClassReference();
- if (classReference1 != null && classReference2 != null) {
- final PsiElement resolved1 = classReference1.resolve();
- final PsiElement resolved2 = classReference2.resolve();
- if (!pattern.getManager().areElementsEquivalent(resolved1, resolved2)) return false;
+ final PsiMethod constructor1 = ((PsiNewExpression)pattern).resolveConstructor();
+ final PsiMethod constructor2 = ((PsiNewExpression)candidate).resolveConstructor();
+ if (constructor1 != null && constructor2 != null) {
+ if (!pattern.getManager().areElementsEquivalent(constructor1, constructor2)) return false;
}
else {
if (!canTypesBeEquivalent(type1, type2)) return false;
import com.intellij.codeInspection.LambdaCanBeMethodReferenceInspection;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
-import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
-import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.Operation;
-import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.TerminalBlock;
+import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.*;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.siyeh.ig.psiutils.ExpressionUtils;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.ListIterator;
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
- if (element instanceof PsiForeachStatement) {
- PsiForeachStatement foreachStatement = (PsiForeachStatement)element;
- PsiStatement body = foreachStatement.getBody();
- final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
- if (body != null && iteratedValue != null) {
- final PsiParameter parameter = foreachStatement.getIterationParameter();
- TerminalBlock tb = TerminalBlock.from(parameter, body);
- if (!FileModificationService.getInstance().preparePsiElementForWrite(foreachStatement)) return;
- PsiElement result = migrate(project, descriptor, foreachStatement, iteratedValue, body, tb);
- if(result != null) {
- simplifyAndFormat(project, result);
- }
+ if (element instanceof PsiLoopStatement) {
+ PsiLoopStatement loopStatement = (PsiLoopStatement)element;
+ StreamSource source = StreamSource.tryCreate(loopStatement);
+ PsiStatement body = loopStatement.getBody();
+ if(body == null || source == null) return;
+ TerminalBlock tb = TerminalBlock.from(source, body);
+ if (!FileModificationService.getInstance().preparePsiElementForWrite(loopStatement)) return;
+ PsiElement result = migrate(project, loopStatement, body, tb);
+ if(result != null) {
+ simplifyAndFormat(project, result);
}
}
}
abstract PsiElement migrate(@NotNull Project project,
- @NotNull ProblemDescriptor descriptor,
- @NotNull PsiForeachStatement foreachStatement,
- @NotNull PsiExpression iteratedValue,
- @NotNull PsiStatement body,
- @NotNull TerminalBlock tb);
+ @NotNull PsiLoopStatement loopStatement,
+ @NotNull PsiStatement body,
+ @NotNull TerminalBlock tb);
static PsiElement replaceWithNumericAddition(@NotNull Project project,
- PsiForeachStatement foreachStatement,
+ PsiLoopStatement loopStatement,
PsiVariable var,
StringBuilder builder,
PsiType expressionType) {
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
- restoreComments(foreachStatement, foreachStatement.getBody());
- InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
+ restoreComments(loopStatement, loopStatement.getBody());
+ InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, loopStatement);
if (status != InitializerUsageStatus.UNKNOWN) {
PsiExpression initializer = var.getInitializer();
if (ExpressionUtils.isZero(initializer)) {
PsiType type = var.getType();
String replacement = (type.equals(expressionType) ? "" : "(" + type.getCanonicalText() + ") ") + builder;
- return replaceInitializer(foreachStatement, var, initializer, replacement, status);
+ return replaceInitializer(loopStatement, var, initializer, replacement, status);
}
}
- return foreachStatement.replace(elementFactory.createStatementFromText(var.getName() + "+=" + builder + ";", foreachStatement));
+ return loopStatement.replace(elementFactory.createStatementFromText(var.getName() + "+=" + builder + ";", loopStatement));
}
- static PsiElement replaceInitializer(PsiForeachStatement foreachStatement,
+ static PsiElement replaceInitializer(PsiLoopStatement loopStatement,
PsiVariable var,
PsiExpression initializer,
String replacement,
InitializerUsageStatus status) {
- Project project = foreachStatement.getProject();
+ Project project = loopStatement.getProject();
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
if(status == InitializerUsageStatus.DECLARED_JUST_BEFORE) {
- initializer.replace(elementFactory.createExpressionFromText(replacement, foreachStatement));
- removeLoop(foreachStatement);
+ initializer.replace(elementFactory.createExpressionFromText(replacement, loopStatement));
+ removeLoop(loopStatement);
return var;
} else {
if(status == InitializerUsageStatus.AT_WANTED_PLACE_ONLY) {
initializer.delete();
}
return
- foreachStatement.replace(elementFactory.createStatementFromText(var.getName() + " = " + replacement + ";", foreachStatement));
+ loopStatement.replace(elementFactory.createStatementFromText(var.getName() + " = " + replacement + ";", loopStatement));
}
}
CodeStyleManager.getInstance(project).reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(result));
}
- static void restoreComments(PsiForeachStatement foreachStatement, PsiStatement body) {
- final PsiElement parent = foreachStatement.getParent();
+ static void restoreComments(PsiLoopStatement loopStatement, PsiStatement body) {
+ final PsiElement parent = loopStatement.getParent();
for (PsiElement comment : PsiTreeUtil.findChildrenOfType(body, PsiComment.class)) {
- parent.addBefore(comment, foreachStatement);
+ parent.addBefore(comment, loopStatement);
}
}
@NotNull
- static StringBuilder generateStream(PsiExpression iteratedValue, @Nullable Operation lastOperation) {
- return generateStream(iteratedValue, lastOperation, false);
+ static StringBuilder generateStream(@NotNull Operation lastOperation) {
+ return generateStream(lastOperation, false);
}
@NotNull
- static StringBuilder generateStream(PsiExpression iteratedValue, @Nullable Operation lastOperation, boolean noStreamForEmpty) {
+ static StringBuilder generateStream(@NotNull Operation lastOperation, boolean noStreamForEmpty) {
StringBuilder buffer = new StringBuilder();
- final PsiType iteratedValueType = iteratedValue.getType();
- if (iteratedValueType instanceof PsiArrayType) {
- buffer.append("java.util.Arrays.stream(").append(iteratedValue.getText()).append(")");
+ if(noStreamForEmpty && lastOperation instanceof CollectionStream) {
+ return buffer.append(lastOperation.getExpression().getText());
}
- else {
- buffer.append(getIteratedValueText(iteratedValue));
- if (!noStreamForEmpty || lastOperation != null) {
- buffer.append(".stream()");
- }
- }
- PsiElementFactory factory = JavaPsiFacade.getElementFactory(iteratedValue.getProject());
List<String> replacements =
- StreamEx.iterate(lastOperation, Objects::nonNull, Operation::getPreviousOp).map(op -> op.createReplacement(factory)).toList();
+ StreamEx.iterate(lastOperation, Objects::nonNull, Operation::getPreviousOp).map(Operation::createReplacement).toList();
for(ListIterator<String> it = replacements.listIterator(replacements.size()); it.hasPrevious(); ) {
buffer.append(it.previous());
}
iteratedValue instanceof PsiParenthesizedExpression ? iteratedValue.getText() : "(" + iteratedValue.getText() + ")";
}
- static void removeLoop(@NotNull PsiForeachStatement statement) {
+ static void removeLoop(@NotNull PsiLoopStatement statement) {
PsiElement parent = statement.getParent();
if (parent instanceof PsiLabeledStatement) {
parent.delete();
*/
package com.intellij.codeInspection.streamMigration;
-import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
+import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.MapOp;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
@Override
PsiElement migrate(@NotNull Project project,
- @NotNull ProblemDescriptor descriptor,
- @NotNull PsiForeachStatement foreachStatement,
- @NotNull PsiExpression iteratedValue,
- @NotNull PsiStatement body,
- @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+ @NotNull PsiLoopStatement loopStatement,
+ @NotNull PsiStatement body,
+ @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
- final PsiType iteratedValueType = iteratedValue.getType();
final PsiMethodCallExpression methodCallExpression = tb.getSingleMethodCall();
if (methodCallExpression == null) return null;
- restoreComments(foreachStatement, body);
- if (!tb.hasOperations() && StreamApiMigrationInspection.isAddAllCall(tb)) {
+ restoreComments(loopStatement, body);
+ if (!tb.hasOperations() && StreamApiMigrationInspection.isAddAllCall(tb) && loopStatement instanceof PsiForeachStatement) {
+ PsiExpression iteratedValue = ((PsiForeachStatement)loopStatement).getIteratedValue();
+ if (iteratedValue == null) return null;
+ final PsiType iteratedValueType = iteratedValue.getType();
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() : "";
final String collectionText =
iteratedValueType instanceof PsiArrayType ? "java.util.Arrays.asList(" + iteratedValue.getText() + ")" :
getIteratedValueText(iteratedValue);
final String callText = StringUtil.getQualifiedName(qualifierText, "addAll(" + collectionText + ");");
- return foreachStatement.replace(elementFactory.createStatementFromText(callText, foreachStatement));
+ return loopStatement.replace(elementFactory.createStatementFromText(callText, loopStatement));
}
PsiExpression itemToAdd = methodCallExpression.getArgumentList().getExpressions()[0];
PsiType addedType = getAddedElementType(methodCallExpression);
if (addedType == null) addedType = itemToAdd.getType();
- final StringBuilder builder =
- generateStream(iteratedValue, new StreamApiMigrationInspection.MapOp(tb.getLastOperation(), itemToAdd, tb.getVariable(), addedType));
+ StringBuilder builder = generateStream(new MapOp(tb.getLastOperation(), itemToAdd, tb.getVariable(), addedType));
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
final PsiLocalVariable variable = StreamApiMigrationInspection.extractCollectionVariable(qualifierExpression);
if (variable != null) {
- InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(variable, foreachStatement);
+ InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(variable, loopStatement);
if(status != InitializerUsageStatus.UNKNOWN) {
PsiExpression initializer = variable.getInitializer();
LOG.assertTrue(initializer != null);
PsiMethodCallExpression toArrayExpression =
- StreamApiMigrationInspection.extractToArrayExpression(foreachStatement, methodCallExpression);
+ StreamApiMigrationInspection.extractToArrayExpression(loopStatement, methodCallExpression);
if(toArrayExpression != null) {
PsiType type = initializer.getType();
if(type instanceof PsiClassType) {
}
PsiElement result =
toArrayExpression.replace(elementFactory.createExpressionFromText(builder.toString(), toArrayExpression));
- removeLoop(foreachStatement);
+ removeLoop(loopStatement);
if(status != InitializerUsageStatus.AT_WANTED_PLACE) {
variable.delete();
}
}
}
}
- PsiElement nextStatement = PsiTreeUtil.skipSiblingsForward(foreachStatement, PsiComment.class, PsiWhiteSpace.class);
+ PsiElement nextStatement = PsiTreeUtil.skipSiblingsForward(loopStatement, PsiComment.class, PsiWhiteSpace.class);
String comparatorText = StreamApiMigrationInspection.tryExtractSortComparatorText(nextStatement, variable);
if(comparatorText != null) {
builder.append(".sorted(").append(comparatorText).append(")");
String callText = builder.append(".collect(java.util.stream.Collectors.")
.append(createInitializerReplacementText(qualifierExpression.getType(), initializer))
.append(")").toString();
- return replaceInitializer(foreachStatement, variable, initializer, callText, status);
+ return replaceInitializer(loopStatement, variable, initializer, callText, status);
}
}
final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() + "." : "";
elementFactory.createExpressionFromText(qualifierText + "add(" + varName + ")", qualifierExpression);
final String callText =
builder.append(".forEach(").append(varName).append("->").append(forEachBody.getText()).append(");").toString();
- return foreachStatement.replace(elementFactory.createStatementFromText(callText, foreachStatement));
+ return loopStatement.replace(elementFactory.createStatementFromText(callText, loopStatement));
}
private static String createInitializerReplacementText(PsiType varType, PsiExpression initializer) {
*/
package com.intellij.codeInspection.streamMigration;
-import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
@Override
PsiElement migrate(@NotNull Project project,
- @NotNull ProblemDescriptor descriptor,
- @NotNull PsiForeachStatement foreachStatement,
- @NotNull PsiExpression iteratedValue,
- @NotNull PsiStatement body,
- @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+ @NotNull PsiLoopStatement loopStatement,
+ @NotNull PsiStatement body,
+ @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
PsiExpression operand = StreamApiMigrationInspection.extractIncrementedLValue(tb.getSingleExpression(PsiExpression.class));
if (!(operand instanceof PsiReferenceExpression)) return null;
PsiElement element = ((PsiReferenceExpression)operand).resolve();
if (!(element instanceof PsiLocalVariable)) return null;
PsiLocalVariable var = (PsiLocalVariable)element;
- final StringBuilder builder = generateStream(iteratedValue, tb.getLastOperation());
- builder.append(".count()");
- return replaceWithNumericAddition(project, foreachStatement, var, builder, PsiType.LONG);
+ StringBuilder builder = generateStream(tb.getLastOperation()).append(".count()");
+ return replaceWithNumericAddition(project, loopStatement, var, builder, PsiType.LONG);
}
}
package com.intellij.codeInspection.streamMigration;
import com.intellij.codeInsight.PsiEquivalenceUtil;
-import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
@Override
PsiElement migrate(@NotNull Project project,
- @NotNull ProblemDescriptor descriptor,
- @NotNull PsiForeachStatement foreachStatement,
- @NotNull PsiExpression iteratedValue,
- @NotNull PsiStatement body,
- @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+ @NotNull PsiLoopStatement loopStatement,
+ @NotNull PsiStatement body,
+ @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
PsiStatement statement = tb.getSingleStatement();
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
- String stream = generateStream(iteratedValue, tb.getLastOperation()).append(".findFirst()").toString();
+ StringBuilder builder = generateStream(tb.getLastOperation());
+ String stream = builder.append(".findFirst()").toString();
if (statement instanceof PsiReturnStatement) {
PsiReturnStatement returnStatement = (PsiReturnStatement)statement;
PsiExpression value = returnStatement.getReturnValue();
if (value == null) return null;
- PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(foreachStatement);
+ PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(loopStatement);
if (nextReturnStatement == null) return null;
PsiExpression orElseExpression = nextReturnStatement.getReturnValue();
if (!ExpressionUtils.isSimpleExpression(orElseExpression)) return null;
stream = generateOptionalUnwrap(stream, tb, value, orElseExpression, null);
- restoreComments(foreachStatement, body);
- if (nextReturnStatement.getParent() == foreachStatement.getParent()) {
+ restoreComments(loopStatement, body);
+ if (nextReturnStatement.getParent() == loopStatement.getParent()) {
nextReturnStatement.delete();
}
- return foreachStatement.replace(elementFactory.createStatementFromText("return " + stream + ";", foreachStatement));
+ return loopStatement.replace(elementFactory.createStatementFromText("return " + stream + ";", loopStatement));
}
else {
PsiStatement[] statements = tb.getStatements();
if (assignment == null) {
if(!(statements[0] instanceof PsiExpressionStatement)) return null;
PsiExpression expression = ((PsiExpressionStatement)statements[0]).getExpression();
- restoreComments(foreachStatement, body);
- return foreachStatement.replace(elementFactory.createStatementFromText(
- stream + ".ifPresent(" + LambdaUtil.createLambda(tb.getVariable(), expression) + ");", foreachStatement));
+ restoreComments(loopStatement, body);
+ return loopStatement.replace(elementFactory.createStatementFromText(
+ stream + ".ifPresent(" + LambdaUtil.createLambda(tb.getVariable(), expression) + ");", loopStatement));
}
PsiExpression lValue = assignment.getLExpression();
if (!(lValue instanceof PsiReferenceExpression)) return null;
PsiVariable var = (PsiVariable)element;
PsiExpression value = assignment.getRExpression();
if (value == null) return null;
- restoreComments(foreachStatement, body);
- InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
+ restoreComments(loopStatement, body);
+ InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, loopStatement);
if (status != InitializerUsageStatus.UNKNOWN) {
PsiExpression initializer = var.getInitializer();
if (initializer != null) {
String replacementText = generateOptionalUnwrap(stream, tb, value, initializer, var.getType());
- return replaceInitializer(foreachStatement, var, initializer, replacementText, status);
+ return replaceInitializer(loopStatement, var, initializer, replacementText, status);
}
}
- return foreachStatement.replace(elementFactory.createStatementFromText(
- var.getName() + " = " + generateOptionalUnwrap(stream, tb, value, lValue, var.getType()) + ";", foreachStatement));
+ return loopStatement.replace(elementFactory.createStatementFromText(
+ var.getName() + " = " + generateOptionalUnwrap(stream, tb, value, lValue, var.getType()) + ";", loopStatement));
}
}
*/
package com.intellij.codeInspection.streamMigration;
-import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
@Override
PsiElement migrate(@NotNull Project project,
- @NotNull ProblemDescriptor descriptor,
- @NotNull PsiForeachStatement foreachStatement,
- @NotNull PsiExpression iteratedValue,
- @NotNull PsiStatement body,
- @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
- restoreComments(foreachStatement, body);
+ @NotNull PsiLoopStatement loopStatement,
+ @NotNull PsiStatement body,
+ @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+ restoreComments(loopStatement, body);
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
- StringBuilder buffer = generateStream(iteratedValue, tb.getLastOperation(), true);
+ StringBuilder buffer = generateStream(tb.getLastOperation(), true);
PsiElement block = tb.convertToElement(elementFactory);
buffer.append(".").append(myForEachMethodName).append("(");
final String functionalExpressionText = tb.getVariable().getName() + " -> " + wrapInBlock(block);
PsiExpressionStatement callStatement = (PsiExpressionStatement)elementFactory
- .createStatementFromText(buffer.toString() + functionalExpressionText + ");", foreachStatement);
- callStatement = (PsiExpressionStatement)foreachStatement.replace(callStatement);
+ .createStatementFromText(buffer.toString() + functionalExpressionText + ");", loopStatement);
+ callStatement = (PsiExpressionStatement)loopStatement.replace(callStatement);
final PsiExpressionList argumentList = ((PsiCallExpression)callStatement.getExpression()).getArgumentList();
LOG.assertTrue(argumentList != null, callStatement.getText());
*/
package com.intellij.codeInspection.streamMigration;
-import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
@Override
PsiElement migrate(@NotNull Project project,
- @NotNull ProblemDescriptor descriptor,
- @NotNull PsiForeachStatement foreachStatement,
- @NotNull PsiExpression iteratedValue,
- @NotNull PsiStatement body,
- @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+ @NotNull PsiLoopStatement loopStatement,
+ @NotNull PsiStatement body,
+ @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
+ StringBuilder builder = generateStream(tb.getLastOperation());
if(tb.getSingleStatement() instanceof PsiReturnStatement) {
PsiReturnStatement returnStatement = (PsiReturnStatement)tb.getSingleStatement();
PsiExpression value = returnStatement.getReturnValue();
if (ExpressionUtils.isLiteral(value, Boolean.TRUE) || ExpressionUtils.isLiteral(value, Boolean.FALSE)) {
boolean foundResult = (boolean)((PsiLiteralExpression)value).getValue();
- PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(foreachStatement);
+ PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(loopStatement);
if (nextReturnStatement != null) {
PsiExpression returnValue = nextReturnStatement.getReturnValue();
if(returnValue == null) return null;
String methodName = foundResult ? "anyMatch" : "noneMatch";
- String streamText = generateStream(iteratedValue, tb.getLastOperation()).toString();
- streamText = addTerminalOperation(streamText, methodName, foreachStatement, tb);
- restoreComments(foreachStatement, body);
- if (nextReturnStatement.getParent() == foreachStatement.getParent()) {
+ String streamText = addTerminalOperation(builder.toString(), methodName, loopStatement, tb);
+ restoreComments(loopStatement, body);
+ if (nextReturnStatement.getParent() == loopStatement.getParent()) {
if(!ExpressionUtils.isLiteral(returnValue, !foundResult)) {
streamText+= (foundResult ? "||" : "&&") + ParenthesesUtils.getText(returnValue, ParenthesesUtils.AND_PRECEDENCE);
}
- removeLoop(foreachStatement);
+ removeLoop(loopStatement);
return returnValue.replace(elementFactory.createExpressionFromText(streamText, nextReturnStatement));
}
- return foreachStatement.replace(elementFactory.createStatementFromText("return " + streamText + ";", foreachStatement));
+ return loopStatement.replace(elementFactory.createStatementFromText("return " + streamText + ";", loopStatement));
}
}
}
PsiStatement[] statements = tb.getStatements();
- if (!(statements.length == 1 || (statements.length == 2 && ControlFlowUtils.statementBreaksLoop(statements[1], foreachStatement)))) {
+ if (!(statements.length == 1 || (statements.length == 2 && ControlFlowUtils.statementBreaksLoop(statements[1], loopStatement)))) {
return null;
}
- restoreComments(foreachStatement, body);
- String streamText = generateStream(iteratedValue, tb.getLastOperation()).toString();
- streamText = addTerminalOperation(streamText, "anyMatch", foreachStatement, tb);
+ restoreComments(loopStatement, body);
+ String streamText = addTerminalOperation(builder.toString(), "anyMatch", loopStatement, tb);
PsiStatement statement = statements[0];
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(statement);
if(assignment != null) {
// for(....) if(...) {flag = true; break;}
PsiVariable var = (PsiVariable)maybeVar;
PsiExpression initializer = var.getInitializer();
- InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
+ InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, loopStatement);
if(initializer != null && status != InitializerUsageStatus.UNKNOWN) {
String replacement;
if(ExpressionUtils.isLiteral(initializer, Boolean.FALSE) &&
} else {
replacement = streamText + "?" + rValue.getText() + ":" + initializer.getText();
}
- return replaceInitializer(foreachStatement, var, initializer, replacement, status);
+ return replaceInitializer(loopStatement, var, initializer, replacement, status);
}
}
}
String replacement = "if(" + streamText + "){" + statement.getText() + "}";
- return foreachStatement.replace(elementFactory.createStatementFromText(replacement, foreachStatement));
+ return loopStatement.replace(elementFactory.createStatementFromText(replacement, loopStatement));
}
private static String addTerminalOperation(String origStream, String methodName, @NotNull PsiElement contextElement,
*/
package com.intellij.codeInspection.streamMigration;
-import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.MapOp;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
@Override
PsiElement migrate(@NotNull Project project,
- @NotNull ProblemDescriptor descriptor,
- @NotNull PsiForeachStatement foreachStatement,
- @NotNull PsiExpression iteratedValue,
- @NotNull PsiStatement body,
- @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+ @NotNull PsiLoopStatement loopStatement,
+ @NotNull PsiStatement body,
+ @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
PsiAssignmentExpression assignment = tb.getSingleExpression(PsiAssignmentExpression.class);
if (assignment == null) return null;
PsiVariable var = StreamApiMigrationInspection.extractAccumulator(assignment);
if (!type.equals(PsiType.DOUBLE) && !type.equals(PsiType.LONG)) {
type = PsiType.INT;
}
- final StringBuilder builder =
- generateStream(iteratedValue, new StreamApiMigrationInspection.MapOp(tb.getLastOperation(), addend, tb.getVariable(), type));
+ StringBuilder builder = generateStream(new MapOp(tb.getLastOperation(), addend, tb.getVariable(), type));
builder.append(".sum()");
- return replaceWithNumericAddition(project, foreachStatement, var, builder, type);
+ return replaceWithNumericAddition(project, loopStatement, var, builder, type);
}
}
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.ig.psiutils.BoolUtils;
import com.siyeh.ig.psiutils.ControlFlowUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
import one.util.streamex.EntryStream;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Contract;
}
static boolean isReferencedInOperations(PsiElement element, TerminalBlock tb) {
- return ReferencesSearch.search(element, new LocalSearchScope(tb.intermediateExpressions().toArray(PsiElement[]::new)))
+ return ReferencesSearch.search(element, new LocalSearchScope(tb.intermediateAndSourceExpressions().toArray(PsiElement[]::new)))
.findFirst() != null;
}
return dependsOnCollection[0];
}
- private static boolean isTrivial(PsiStatement body, PsiParameter parameter) {
+ @Contract("_, null -> false")
+ private static boolean isTrivial(PsiStatement body, PsiLoopStatement loopStatement) {
+ if(!(loopStatement instanceof PsiForeachStatement)) return false;
+ PsiParameter parameter = ((PsiForeachStatement)loopStatement).getIterationParameter();
//method reference
final PsiExpression candidate = new LambdaCanBeMethodReferenceInspection()
.canBeMethodReferenceProblem(body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : body,
return consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, variable.getType()) : null;
}
+ static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement) {
+ PsiElement declaration = variable.getParent();
+ // For-loop initializer is not effectively final, but suitable for stream conversion
+ if(declaration instanceof PsiDeclarationStatement) {
+ PsiElement grandParent = declaration.getParent();
+ if (grandParent instanceof PsiForStatement) {
+ PsiForStatement forStatement = (PsiForStatement)grandParent;
+ if (forStatement.getInitialization() == declaration) {
+ PsiStatement body = forStatement.getBody();
+ if(body != null && PsiTreeUtil.isAncestor(statement, body, false)) {
+ return ReferencesSearch.search(variable, new LocalSearchScope(body)).forEach(ref -> {
+ PsiElement element = ref.getElement();
+ return !(element instanceof PsiExpression) || !PsiUtil.isAccessedForWriting((PsiExpression)element);
+ });
+ }
+ }
+ }
+ }
+ return HighlightControlFlowUtil.isEffectivelyFinal(variable, statement, null);
+ }
+
@Contract("null -> null")
static PsiLocalVariable extractCollectionVariable(PsiExpression qualifierExpression) {
if (qualifierExpression instanceof PsiReferenceExpression) {
@Override
public void visitForeachStatement(PsiForeachStatement statement) {
super.visitForeachStatement(statement);
- final PsiExpression iteratedValue = statement.getIteratedValue();
+ processLoop(statement);
+ }
+
+ @Override
+ public void visitForStatement(PsiForStatement statement) {
+ super.visitForStatement(statement);
+ processLoop(statement);
+ }
+
+ void processLoop(PsiLoopStatement statement) {
final PsiStatement body = statement.getBody();
- if (iteratedValue == null || body == null) return;
-
- final PsiType iteratedValueType = iteratedValue.getType();
- final PsiClass iteratorClass = PsiUtil.resolveClassInClassTypeOnly(iteratedValueType);
- PsiClass collectionClass = null;
- final boolean isArray;
- if(iteratedValueType instanceof PsiArrayType) {
- if(!isSupported(((PsiArrayType)iteratedValueType).getComponentType())) return;
- isArray = true;
- } else {
- collectionClass = JavaPsiFacade.getInstance(body.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, statement.getResolveScope());
- if (collectionClass != null && InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true)) {
- isArray = false;
- } else return;
- }
+ if(body == null) return;
+ StreamSource source = StreamSource.tryCreate(statement);
+ if(source == null) return;
if (!ExceptionUtil.getThrownCheckedExceptions(body).isEmpty()) return;
-
- TerminalBlock tb = TerminalBlock.from(statement.getIterationParameter(), body);
+ TerminalBlock tb = TerminalBlock.from(source, body);
if(tb.isEmpty()) return;
final ControlFlow controlFlow;
int startOffset = controlFlow.getStartOffset(body);
int endOffset = controlFlow.getEndOffset(body);
final List<PsiVariable> nonFinalVariables = StreamEx.of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset))
- .remove(variable -> HighlightControlFlowUtil.isEffectivelyFinal(variable, body, null)).toList();
+ .remove(variable -> isVariableSuitableForStream(variable, statement)).toList();
if (exitPoints.isEmpty()) {
if(getIncrementedVariable(tb, nonFinalVariables) != null) {
if(!nonFinalVariables.isEmpty()) {
return;
}
- if ((isArray || !isRawSubstitution(iteratedValueType, collectionClass)) && isCollectCall(tb)) {
- boolean addAll = !tb.hasOperations() && isAddAllCall(tb);
+ if (isCollectCall(tb)) {
+ boolean addAll = statement instanceof PsiForeachStatement && !tb.hasOperations() && isAddAllCall(tb);
String methodName;
if(addAll) {
methodName = "addAll";
}
// do not replace for(T e : arr) {} with Arrays.stream(arr).forEach(e -> {}) even if flag is set
else if (SUGGEST_FOREACH &&
- (tb.hasOperations() || (!isArray && (REPLACE_TRIVIAL_FOREACH || !isTrivial(body, statement.getIterationParameter()))))) {
+ (tb.hasOperations() || (!(source instanceof ArrayStream) && (REPLACE_TRIVIAL_FOREACH || !isTrivial(body, statement))))) {
ReplaceWithForeachCallFix forEachFix = new ReplaceWithForeachCallFix("forEach");
LocalQuickFix[] fixes = {forEachFix};
if (tb.hasOperations()) { //for .stream()
if (nonFinalVariables.isEmpty() && tb.getSingleStatement() instanceof PsiReturnStatement) {
handleSingleReturn(statement, tb);
}
- // Intermediate ops should not refer to non-final variables
- if (tb.intermediateExpressions()
+ // Source and intermediate ops should not refer to non-final variables
+ if (tb.intermediateAndSourceExpressions()
.flatCollection(expr -> PsiTreeUtil.collectElementsOfType(expr, PsiReferenceExpression.class))
.map(PsiReferenceExpression::resolve).anyMatch(nonFinalVariables::contains)) {
return;
return;
}
if (ReferencesSearch.search(tb.getVariable(), new LocalSearchScope(statements)).findFirst() == null
- && exitPoints.size() == 1 && exitPoints.contains(breakStatement)) {
+ && exitPoints.size() == 1 && exitPoints.contains(breakStatement)) {
registerProblem(statement, "anyMatch", new ReplaceWithMatchFix("anyMatch"));
return;
}
}
}
- boolean canCollect(PsiForeachStatement statement, PsiMethodCallExpression methodCallExpression) {
+ boolean canCollect(PsiLoopStatement statement, PsiMethodCallExpression methodCallExpression) {
if(methodCallExpression == null) return false;
PsiLocalVariable variable = extractCollectionVariable(methodCallExpression.getMethodExpression().getQualifierExpression());
if(variable == null) return false;
return getInitializerUsageStatus(variable, statement) != UNKNOWN;
}
- void handleSingleReturn(PsiForeachStatement statement, TerminalBlock tb) {
+ void handleSingleReturn(PsiLoopStatement statement, TerminalBlock tb) {
PsiReturnStatement returnStatement = (PsiReturnStatement)tb.getSingleStatement();
PsiExpression value = returnStatement.getReturnValue();
PsiReturnStatement nextReturnStatement = getNextReturnStatement(statement);
}
if (!isVariableReferenced(tb.getVariable(), value)) {
Operation lastOp = tb.getLastOperation();
- if(!REPLACE_TRIVIAL_FOREACH && lastOp == null || (lastOp instanceof FilterOp && lastOp.getPreviousOp() == null)) return;
+ if (!REPLACE_TRIVIAL_FOREACH && lastOp instanceof StreamSource ||
+ (lastOp instanceof FilterOp && lastOp.getPreviousOp() instanceof StreamSource)) {
+ return;
+ }
registerProblem(statement, "anyMatch", new ReplaceWithMatchFix("anyMatch"));
}
if(nextReturnStatement != null && ExpressionUtils.isSimpleExpression(nextReturnStatement.getReturnValue())
}
}
- private boolean isRawSubstitution(PsiType iteratedValueType, PsiClass collectionClass) {
- return iteratedValueType instanceof PsiClassType && PsiUtil
- .isRawSubstitutor(collectionClass, TypeConversionUtil.getSuperClassSubstitutor(collectionClass, (PsiClassType)iteratedValueType));
- }
-
@NotNull
- private TextRange getRange(PsiForeachStatement statement) {
+ private TextRange getRange(PsiLoopStatement statement) {
boolean wholeStatement = false;
if(myIsOnTheFly) {
if (myKey == null) {
wholeStatement = HighlightDisplayLevel.DO_NOT_SHOW.equals(level);
}
}
- PsiExpression iteratedValue = statement.getIteratedValue();
- LOG.assertTrue(iteratedValue != null);
- PsiJavaToken rParenth = statement.getRParenth();
- if(wholeStatement && rParenth != null) {
- return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
+ if(statement instanceof PsiForeachStatement) {
+ PsiJavaToken rParenth = ((PsiForeachStatement)statement).getRParenth();
+ if (wholeStatement && rParenth != null) {
+ return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
+ }
+ PsiExpression iteratedValue = ((PsiForeachStatement)statement).getIteratedValue();
+ LOG.assertTrue(iteratedValue != null);
+ return iteratedValue.getTextRange();
+ } else if(statement instanceof PsiForStatement) {
+ PsiJavaToken rParenth = ((PsiForStatement)statement).getRParenth();
+ if (wholeStatement && rParenth != null) {
+ return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
+ }
+ PsiStatement initialization = ((PsiForStatement)statement).getInitialization();
+ LOG.assertTrue(initialization != null);
+ return initialization.getTextRange();
+ } else {
+ throw new IllegalStateException("Unexpected statement type: "+statement);
}
- return iteratedValue.getTextRange();
}
- private void registerProblem(PsiForeachStatement statement, String methodName, LocalQuickFix... fixes) {
- PsiExpression iteratedValue = statement.getIteratedValue();
- LOG.assertTrue(iteratedValue != null);
+ private void registerProblem(PsiLoopStatement statement, String methodName, LocalQuickFix... fixes) {
myHolder.registerProblem(statement, getRange(statement).shiftRight(-statement.getTextOffset()),
"Can be replaced with '" + methodName + "' call", fixes);
}
}
@Nullable
- static PsiMethodCallExpression extractToArrayExpression(PsiForeachStatement statement, PsiMethodCallExpression expression) {
+ static PsiMethodCallExpression extractToArrayExpression(PsiLoopStatement statement, PsiMethodCallExpression expression) {
// return collection.toArray() or collection.toArray(new Type[0]) or collection.toArray(new Type[collection.size()]);
PsiElement nextElement = PsiTreeUtil.skipSiblingsForward(statement, PsiComment.class, PsiWhiteSpace.class);
PsiExpression toArrayCandidate;
return StreamEx.of(myExpression);
}
- abstract String createReplacement(PsiElementFactory factory);
+ abstract String createReplacement();
}
static class FilterOp extends Operation {
}
@Override
- public String createReplacement(PsiElementFactory factory) {
+ public String createReplacement() {
+ PsiElementFactory factory = JavaPsiFacade.getElementFactory(myExpression.getProject());
PsiExpression intermediate = makeIntermediateExpression(factory);
PsiExpression expression =
myNegated ? factory.createExpressionFromText(BoolUtils.getNegatedExpressionText(intermediate), myExpression) : intermediate;
}
@Override
- public String createReplacement(PsiElementFactory factory) {
+ public String createReplacement() {
if (isIdentityMapping(myVariable, myExpression)) {
if (!(myType instanceof PsiPrimitiveType)) {
return myVariable.getType() instanceof PsiPrimitiveType ? ".boxed()" : "";
static class FlatMapOp extends Operation {
private final PsiLoopStatement myLoop;
+ private final StreamSource mySource;
- FlatMapOp(@Nullable Operation previousOp, PsiExpression expression, PsiVariable variable, PsiLoopStatement loop) {
- super(previousOp, expression, variable);
+ FlatMapOp(@Nullable Operation previousOp, StreamSource source, PsiVariable variable, PsiLoopStatement loop) {
+ super(previousOp, source.getExpression(), variable);
myLoop = loop;
+ mySource = source;
}
@Override
- public String createReplacement(PsiElementFactory factory) {
- return ".flatMap(" + myVariable.getName() + " -> " + getStreamExpression() + ")";
+ public String createReplacement() {
+ String operation = "flatMap";
+ PsiType type = mySource.getVariable().getType();
+ if(type instanceof PsiPrimitiveType && !type.equals(myVariable.getType())) {
+ if(type.equals(PsiType.INT)) {
+ operation = "flatMapToInt";
+ } else if(type.equals(PsiType.LONG)) {
+ operation = "flatMapToLong";
+ } else if(type.equals(PsiType.DOUBLE)) {
+ operation = "flatMapToDouble";
+ }
+ }
+ return "." + operation + "(" + myVariable.getName() + " -> " + getStreamExpression() + ")";
}
@NotNull
String getStreamExpression() {
- return myExpression.getText() + ".stream()";
+ return mySource.createReplacement();
}
boolean breaksMe(PsiBreakStatement statement) {
}
}
- static class ArrayFlatMapOp extends FlatMapOp {
- ArrayFlatMapOp(@Nullable Operation previousOp, PsiExpression expression, PsiVariable variable, PsiLoopStatement loop) {
- super(previousOp, expression, variable, loop);
+ abstract static class StreamSource extends Operation {
+ protected StreamSource(PsiVariable variable, PsiExpression expression) {
+ super(null, expression, variable);
}
- @Override
- public String createReplacement(PsiElementFactory factory) {
- String operation = "flatMap";
- PsiType type = myExpression.getType();
- if(type instanceof PsiArrayType) {
- PsiType componentType = ((PsiArrayType)type).getComponentType();
- if(componentType instanceof PsiPrimitiveType) {
- if(componentType.equals(PsiType.INT)) {
- operation = "flatMapToInt";
- } else if(componentType.equals(PsiType.LONG)) {
- operation = "flatMapToLong";
- } else if(componentType.equals(PsiType.DOUBLE)) {
- operation = "flatMapToDouble";
- }
- }
+ @Contract("null -> null")
+ static StreamSource tryCreate(PsiLoopStatement statement) {
+ if(statement instanceof PsiForStatement) {
+ return CountingLoop.from((PsiForStatement)statement);
}
- return "." + operation + "(" + myVariable.getName() + " -> " + getStreamExpression() + ")";
+ if(statement instanceof PsiForeachStatement) {
+ ArrayStream source = ArrayStream.from((PsiForeachStatement)statement);
+ return source == null ? CollectionStream.from((PsiForeachStatement)statement) : source;
+ }
+ return null;
+ }
+ }
+
+ static class ArrayStream extends StreamSource {
+ private ArrayStream(PsiVariable variable, PsiExpression expression) {
+ super(variable, expression);
}
@Override
- @NotNull
- String getStreamExpression() {
+ String createReplacement() {
return "java.util.Arrays.stream("+myExpression.getText() + ")";
}
+
+ @Nullable
+ public static ArrayStream from(PsiForeachStatement statement) {
+ PsiExpression iteratedValue = statement.getIteratedValue();
+ if (iteratedValue == null) return null;
+
+ PsiType iteratedValueType = iteratedValue.getType();
+ PsiParameter parameter = statement.getIterationParameter();
+
+ if (!(iteratedValueType instanceof PsiArrayType) ||
+ !isSupported(((PsiArrayType)iteratedValueType).getComponentType()) ||
+ ((parameter.getType() instanceof PsiPrimitiveType) &&
+ !parameter.getType().equals(((PsiArrayType)iteratedValueType).getComponentType()))) {
+ return null;
+ }
+
+ return new ArrayStream(parameter, iteratedValue);
+ }
+ }
+
+ static class CollectionStream extends StreamSource {
+
+ private CollectionStream(PsiVariable variable, PsiExpression expression) {
+ super(variable, expression);
+ }
+
+ @Override
+ String createReplacement() {
+ return ParenthesesUtils.getText(myExpression, ParenthesesUtils.POSTFIX_PRECEDENCE) + ".stream()";
+ }
+
+ @Contract("null, _ -> false")
+ static boolean isRawSubstitution(PsiType iteratedValueType, PsiClass collectionClass) {
+ return iteratedValueType instanceof PsiClassType && PsiUtil
+ .isRawSubstitutor(collectionClass, TypeConversionUtil.getSuperClassSubstitutor(collectionClass, (PsiClassType)iteratedValueType));
+ }
+
+ @Nullable
+ public static CollectionStream from(PsiForeachStatement statement) {
+ PsiExpression iteratedValue = statement.getIteratedValue();
+ if (iteratedValue == null) return null;
+
+ PsiType iteratedValueType = iteratedValue.getType();
+ PsiClass collectionClass =
+ JavaPsiFacade.getInstance(statement.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, statement.getResolveScope());
+ PsiClass iteratorClass = PsiUtil.resolveClassInClassTypeOnly(iteratedValueType);
+ if (collectionClass == null ||
+ !InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true) ||
+ isRawSubstitution(iteratedValueType, collectionClass)) {
+ return null;
+ }
+ return new CollectionStream(statement.getIterationParameter(), iteratedValue);
+ }
+ }
+
+ static class CountingLoop extends StreamSource {
+ final PsiExpression myBound;
+ final boolean myIncluding;
+
+ private CountingLoop(PsiLocalVariable counter, PsiExpression initializer, PsiExpression bound, boolean including) {
+ super(counter, initializer);
+ myBound = bound;
+ myIncluding = including;
+ }
+
+ @Override
+ StreamEx<PsiExpression> expressions() {
+ return StreamEx.of(myExpression, myBound);
+ }
+
+ @Override
+ public String createReplacement() {
+ String className = myVariable.getType().equals(PsiType.LONG) ? "java.util.stream.LongStream" : "java.util.stream.IntStream";
+ String methodName = myIncluding ? "rangeClosed" : "range";
+ return className+"."+methodName+"("+myExpression.getText()+", "+myBound.getText()+")";
+ }
+
+ @Nullable
+ public static CountingLoop from(PsiForStatement forStatement) {
+ // check that initialization is for(int/long i = <initial_value>;...;...)
+ if(!(forStatement.getInitialization() instanceof PsiDeclarationStatement)) return null;
+ PsiDeclarationStatement initialization = (PsiDeclarationStatement)forStatement.getInitialization();
+ if(initialization.getDeclaredElements().length != 1) return null;
+ PsiElement declaration = initialization.getDeclaredElements()[0];
+ if(!(declaration instanceof PsiLocalVariable)) return null;
+ PsiLocalVariable counter = (PsiLocalVariable)declaration;
+ if(!counter.getType().equals(PsiType.INT) && !counter.getType().equals(PsiType.LONG)) return null;
+
+ PsiExpression initializer = counter.getInitializer();
+ if(initializer == null) return null;
+
+ // check that increment is like for(...;...;i++)
+ if(!(forStatement.getUpdate() instanceof PsiExpressionStatement)) return null;
+ PsiExpression lValue = extractIncrementedLValue(((PsiExpressionStatement)forStatement.getUpdate()).getExpression());
+ if(!(lValue instanceof PsiReferenceExpression) || ((PsiReferenceExpression)lValue).resolve() != counter) return null;
+
+ // check that condition is like for(...;i<bound;...) or for(...;i<=bound;...)
+ if(!(forStatement.getCondition() instanceof PsiBinaryExpression)) return null;
+ PsiBinaryExpression condition = (PsiBinaryExpression)forStatement.getCondition();
+ IElementType type = condition.getOperationTokenType();
+ boolean closed = false;
+ PsiExpression bound;
+ PsiExpression ref;
+ if(type.equals(JavaTokenType.LE)) {
+ bound = condition.getROperand();
+ ref = condition.getLOperand();
+ closed = true;
+ } else if(type.equals(JavaTokenType.LT)) {
+ bound = condition.getROperand();
+ ref = condition.getLOperand();
+ } else if(type.equals(JavaTokenType.GE)) {
+ bound = condition.getLOperand();
+ ref = condition.getROperand();
+ closed = true;
+ } else if(type.equals(JavaTokenType.GT)) {
+ bound = condition.getLOperand();
+ ref = condition.getROperand();
+ } else return null;
+ if(bound == null || !(ref instanceof PsiReferenceExpression) || ((PsiReferenceExpression)ref).resolve() != counter) return null;
+ if(!TypeConversionUtil.areTypesAssignmentCompatible(counter.getType(), bound)) return null;
+ return new CountingLoop(counter, initializer, bound, closed);
+ }
}
/**
* some intermediate operations extracted.
*/
static class TerminalBlock {
- private final @Nullable Operation myPreviousOp;
+ private final @NotNull Operation myPreviousOp;
private final @NotNull PsiVariable myVariable;
private final @NotNull PsiStatement[] myStatements;
- private TerminalBlock(@Nullable Operation previousOp, @NotNull PsiVariable variable, @NotNull PsiStatement... statements) {
+ // At least one previous operation is present (stream source)
+ private TerminalBlock(@NotNull Operation previousOp, @NotNull PsiVariable variable, @NotNull PsiStatement... statements) {
myVariable = variable;
while(true) {
if(statements.length == 1 && statements[0] instanceof PsiBlockStatement) {
TerminalBlock withFilter = extractFilter();
if(withFilter != null) return withFilter;
// extract flatMap
- if(getSingleStatement() instanceof PsiForeachStatement) {
- // flatMapping of primitive variable is not supported yet
- if(myVariable.getType() instanceof PsiPrimitiveType) return null;
- PsiForeachStatement foreachStatement = (PsiForeachStatement)getSingleStatement();
- final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
- final PsiStatement body = foreachStatement.getBody();
- if (iteratedValue != null && body != null) {
- final PsiType iteratedValueType = iteratedValue.getType();
- FlatMapOp op = null;
- if(iteratedValueType instanceof PsiArrayType) {
- if (!isSupported(((PsiArrayType)iteratedValueType).getComponentType())) return null;
- op = new ArrayFlatMapOp(myPreviousOp, iteratedValue, myVariable, foreachStatement);
- } else {
- final PsiClass iteratorClass = PsiUtil.resolveClassInClassTypeOnly(iteratedValueType);
- final PsiClass collectionClass =
- JavaPsiFacade.getInstance(body.getProject())
- .findClass(CommonClassNames.JAVA_UTIL_COLLECTION, foreachStatement.getResolveScope());
- if (collectionClass != null && InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true)) {
- op = new FlatMapOp(myPreviousOp, iteratedValue, myVariable, foreachStatement);
- }
- }
- if(op != null) {
- TerminalBlock withFlatMap = new TerminalBlock(op, foreachStatement.getIterationParameter(), body);
- if(ReferencesSearch.search(myVariable, new LocalSearchScope(body)).findFirst() == null) {
- return withFlatMap;
- } else {
- // Try extract nested filter like this:
- // for(List subList : list) for(T t : subList) if(condition.test(t)) { ...; break; }
- // if t is not used in "...", then this could be converted to
- // list.stream().filter(subList -> subList.stream().anyMatch(condition)).forEach(subList -> ...)
- TerminalBlock withFlatMapFilter = withFlatMap.extractFilter();
- if(withFlatMapFilter != null && !withFlatMapFilter.isEmpty()) {
- PsiStatement[] statements = withFlatMapFilter.getStatements();
- PsiStatement lastStatement = statements[statements.length-1];
- if (lastStatement instanceof PsiBreakStatement && op.breaksMe((PsiBreakStatement)lastStatement) &&
- ReferencesSearch.search(withFlatMapFilter.getVariable(), new LocalSearchScope(statements)).findFirst() == null) {
- return new TerminalBlock(new CompoundFilterOp((FilterOp)withFlatMapFilter.getLastOperation(), op),
- myVariable, Arrays.copyOfRange(statements, 0, statements.length-1));
- }
- }
+ if(getSingleStatement() instanceof PsiLoopStatement) {
+ PsiLoopStatement loopStatement = (PsiLoopStatement)getSingleStatement();
+ StreamSource source = StreamSource.tryCreate(loopStatement);
+ final PsiStatement body = loopStatement.getBody();
+ if(source == null || body == null) return null;
+ // flatMap from primitive to primitive is supported only if primitive types match
+ // otherwise it would be necessary to create bogus step like
+ // .mapToObj(var -> blahblah.stream()).flatMap(Function.identity())
+ if(myVariable.getType() instanceof PsiPrimitiveType && !myVariable.getType().equals(source.getVariable().getType())) return null;
+ FlatMapOp op = new FlatMapOp(myPreviousOp, source, myVariable, loopStatement);
+ TerminalBlock withFlatMap = new TerminalBlock(op, source.getVariable(), body);
+ if(ReferencesSearch.search(myVariable, new LocalSearchScope(body)).findFirst() == null) {
+ return withFlatMap;
+ } else {
+ // Try extract nested filter like this:
+ // for(List subList : list) for(T t : subList) if(condition.test(t)) { ...; break; }
+ // if t is not used in "...", then this could be converted to
+ // list.stream().filter(subList -> subList.stream().anyMatch(condition)).forEach(subList -> ...)
+ TerminalBlock withFlatMapFilter = withFlatMap.extractFilter();
+ if(withFlatMapFilter != null && !withFlatMapFilter.isEmpty()) {
+ PsiStatement[] statements = withFlatMapFilter.getStatements();
+ PsiStatement lastStatement = statements[statements.length-1];
+ if (lastStatement instanceof PsiBreakStatement && op.breaksMe((PsiBreakStatement)lastStatement) &&
+ ReferencesSearch.search(withFlatMapFilter.getVariable(), new LocalSearchScope(statements)).findFirst() == null) {
+ return new TerminalBlock(new CompoundFilterOp((FilterOp)withFlatMapFilter.getLastOperation(), op),
+ myVariable, Arrays.copyOfRange(statements, 0, statements.length-1));
}
}
}
return null;
}
- @Nullable
+ @NotNull
public Operation getLastOperation() {
return myPreviousOp;
}
}
public boolean hasOperations() {
- return myPreviousOp != null;
+ return !(myPreviousOp instanceof StreamSource);
}
public boolean isEmpty() {
* @return stream of physical expressions used in intermediate operations in arbitrary order
*/
public StreamEx<PsiExpression> intermediateExpressions() {
+ return operations().remove(StreamSource.class::isInstance).flatMap(Operation::expressions);
+ }
+
+ /**
+ * @return stream of physical expressions used in stream source and intermediate operations in arbitrary order
+ */
+ public StreamEx<PsiExpression> intermediateAndSourceExpressions() {
return operations().flatMap(Operation::expressions);
}
}
@NotNull
- public static TerminalBlock from(PsiVariable variable, PsiStatement statement) {
- return new TerminalBlock(null, variable, statement).extractOperations();
+ public static TerminalBlock from(StreamSource source, PsiStatement body) {
+ return new TerminalBlock(source, source.myVariable, body).extractOperations();
}
}
}
}
final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getInstance(psiFile.getProject()).getCurrentSettings();
- final int indentSize = codeStyleSettings.getIndentSize(psiFile.getFileType());
int column;
if (codeStyleSettings.JD_ALIGN_PARAM_COMMENTS) {
column = Math.max(descriptionStartColumn, parameterNameEndColumn);
if (column <= parameterNameEndColumn) {
- column = parameterNameEndColumn + indentSize;
+ column = parameterNameEndColumn + 1;
}
}
else {
- column = anchor.parameterNameEndPosition.column + indentSize;
+ column = anchor.parameterNameEndPosition.column + 1;
}
return new LogicalPosition(anchor.parameterNameEndPosition.line, column);
}
return elementFactory.createType(parameter);
}
- public void initExpressionConstraints(PsiParameter[] parameters, PsiExpression[] args, PsiElement parent, PsiMethod method) {
+ public void initExpressionConstraints(PsiParameter[] parameters, PsiExpression[] args, PsiElement parent) {
final MethodCandidateInfo.CurrentCandidateProperties currentProperties = getCurrentProperties(parent);
- initExpressionConstraints(parameters, args, parent, method, currentProperties != null && currentProperties.isVarargs());
+ initExpressionConstraints(parameters, args, parent, null, currentProperties != null && currentProperties.isVarargs());
}
public void initExpressionConstraints(PsiParameter[] parameters,
final Ref<String> errorMessage = new Ref<String>();
final PsiType targetType = getTargetTypeFromParent(parent, errorMessage, false);
if (targetType == null && errorMessage.get() != null) {
- registerIncompatibleErrorMessage(errorMessage.get());
return;
}
}
if (!repeatInferencePhases()) {
+ resolveBounds(getInputInferenceVariablesFromTopLevelFunctionalExpressions(args, properties), initialSubstitutor);
return;
}
}
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints, ignoredConstraints)) {
+ resolveBounds(getInputInferenceVariablesFromTopLevelFunctionalExpressions(args, properties), initialSubstitutor);
return;
}
}
}
- final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables, initialSubstitutor);
- if (substitutor != null) {
- if (myContext != null) {
- myContext.putUserData(ERASED, myErased);
- }
- final Map<PsiTypeParameter, PsiType> map = substitutor.getSubstitutionMap();
- for (PsiTypeParameter parameter : map.keySet()) {
- final PsiType mapping = map.get(parameter);
- PsiTypeParameter param;
- if (parameter instanceof InferenceVariable) {
- ((InferenceVariable)parameter).setInstantiation(mapping);
- if (((InferenceVariable)parameter).getCallContext() != myContext) {
- //don't include in result substitutor foreign inference variables
- continue;
+ resolveBounds(myInferenceVariables, initialSubstitutor);
+ }
+
+ private Collection<InferenceVariable> getInputInferenceVariablesFromTopLevelFunctionalExpressions(PsiExpression[] args, MethodCandidateInfo.CurrentCandidateProperties properties) {
+ if (args == null) return Collections.emptyList();
+ final PsiMethod method = properties.getMethod();
+ final PsiParameter[] parameters = method.getParameterList().getParameters();
+ final HashSet<InferenceVariable> dependencies = new HashSet<InferenceVariable>();
+ for (int i = 0; i < args.length; i++) {
+ PsiExpression arg = args[i];
+ if (arg instanceof PsiLambdaExpression && !((PsiLambdaExpression)arg).hasFormalParameterTypes() ||
+ arg instanceof PsiMethodReferenceExpression && !((PsiMethodReferenceExpression)arg).isExact()) {
+ final PsiSubstitutor nestedSubstitutor = myInferenceSessionContainer.findNestedSubstitutor(arg, myInferenceSubstitution);
+ final PsiType parameterType = nestedSubstitutor.substitute(getParameterType(parameters, i, mySiteSubstitutor, properties.isVarargs()));
+ final PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(parameterType);
+ final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(result);
+ if (interfaceMethod != null) {
+ final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, result);
+ for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
+ collectDependencies(substitutor.substitute(parameter.getType()), dependencies);
}
- param = ((InferenceVariable)parameter).getParameter();
}
- else {
- param = parameter;
- }
- mySiteSubstitutor = mySiteSubstitutor.put(param, mapping);
}
}
+ return dependencies;
}
private boolean isOverloadCheck() {
return false;
}
- private PsiSubstitutor resolveBounds(final Collection<InferenceVariable> inferenceVariables,
- PsiSubstitutor substitutor) {
+ private void resolveBounds(final Collection<InferenceVariable> inferenceVariables,
+ @NotNull PsiSubstitutor substitutor) {
final Collection<InferenceVariable> allVars = new ArrayList<InferenceVariable>(inferenceVariables);
while (!allVars.isEmpty()) {
final List<InferenceVariable> vars = InferenceVariablesOrder.resolveOrder(allVars, this);
}
if (!initFreshVariables(substitutor, unresolved)) {
- return null;
+ return;
}
myIncorporationPhase.forgetCaptures(vars);
if (!repeatInferencePhases()) {
- return null;
+ return;
}
}
- return substitutor;
+
+ if (myContext != null) {
+ myContext.putUserData(ERASED, myErased);
+ }
+
+ final Map<PsiTypeParameter, PsiType> map = substitutor.getSubstitutionMap();
+ for (PsiTypeParameter parameter : map.keySet()) {
+ final PsiType mapping = map.get(parameter);
+ PsiTypeParameter param;
+ if (parameter instanceof InferenceVariable) {
+ ((InferenceVariable)parameter).setInstantiation(mapping);
+ if (((InferenceVariable)parameter).getCallContext() != myContext) {
+ //don't include in result substitutor foreign inference variables
+ continue;
+ }
+ param = ((InferenceVariable)parameter).getParameter();
+ }
+ else {
+ param = parameter;
+ }
+ mySiteSubstitutor = mySiteSubstitutor.put(param, mapping);
+ }
}
private boolean initFreshVariables(PsiSubstitutor substitutor, List<InferenceVariable> vars) {
}
final InferenceSession inferenceSession = new InferenceSession(typeParameters, partialSubstitutor, parent.getManager(), parent, policy);
- inferenceSession.initExpressionConstraints(parameters, arguments, parent, null);
+ inferenceSession.initExpressionConstraints(parameters, arguments, parent);
return inferenceSession.infer(parameters, arguments, parent);
}
}
else {
final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParameter}, partialSubstitutor, myManager, null);
- inferenceSession.initExpressionConstraints(parameters, arguments, null, null);
+ inferenceSession.initExpressionConstraints(parameters, arguments, null);
substitutor = inferenceSession.infer();
}
return substitutor.substitute(typeParameter);
class Main {
void foo(List<Integer> list) {
- bar(list, i -> <error descr="Bad return type in lambda expression: int cannot be converted to S_OUT">i.intValue()</error>, i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
- bar1(list, i -> <error descr="Bad return type in lambda expression: int cannot be converted to S_OUT">i.intValue()</error>, i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
+ bar(list, i -> i.intValue(), i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
+ bar1(list, i -> i.intValue(), i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
}
<U, S_IN, S_OUT, R> R bar(List<S_IN> list,
}
public static void main(String[] args) {
- <error descr="Ambiguous method call: both 'ReturnTypeCompatibility.call(I1<Number>)' and 'ReturnTypeCompatibility.call(I2<P>)' match">call</error>(i-> {return i;});
+ <error descr="Ambiguous method call: both 'ReturnTypeCompatibility.call(I1<Number>)' and 'ReturnTypeCompatibility.call(I2<String>)' match">call</error>(i-> {return i;});
}
}