Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2016-10-07 10:07:28 +03:00
899 changed files with 4815 additions and 1232 deletions
+26 -22
View File
@@ -1,31 +1,35 @@
<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>
@@ -125,9 +125,9 @@ class CommunityLibraryLicenses {
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"),
+4
View File
@@ -24,6 +24,10 @@ target('default': 'Downloads custom JRE build from Teamcity server') {
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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 179 B

@@ -0,0 +1,9 @@
<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>

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 B

After

Width:  |  Height:  |  Size: 272 B

@@ -0,0 +1,9 @@
<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>

After

Width:  |  Height:  |  Size: 612 B

@@ -22,6 +22,7 @@ import com.intellij.execution.runners.ExecutionEnvironment;
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;
@@ -45,6 +46,8 @@ import java.util.stream.Stream;
* @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,
@@ -89,39 +92,60 @@ public class InternalProjectTaskRunner extends ProjectTaskRunner {
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);
@@ -26,10 +26,21 @@ import org.jetbrains.annotations.NotNull;
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
@@ -38,6 +49,16 @@ public class ModuleBuildTaskImpl extends AbstractBuildTask implements ModuleBuil
return myModule;
}
@Override
public boolean isIncludeDependentModules() {
return myIncludeDependentModules;
}
@Override
public boolean isIncludeRuntimeDependencies() {
return myIncludeRuntimeDependencies;
}
@NotNull
@Override
public String getPresentableName() {
@@ -25,6 +25,7 @@ import com.intellij.packaging.artifacts.Artifact;
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;
@@ -50,12 +51,12 @@ public class ProjectTaskManagerImpl extends ProjectTaskManager {
@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
@@ -91,14 +92,26 @@ public class ProjectTaskManagerImpl extends ProjectTaskManager {
@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
@@ -25,4 +25,8 @@ import org.jetbrains.annotations.NotNull;
public interface ModuleBuildTask extends BuildTask {
@NotNull
Module getModule();
boolean isIncludeDependentModules();
boolean isIncludeRuntimeDependencies();
}
@@ -91,7 +91,15 @@ public abstract class ProjectTaskManager {
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);
@@ -164,7 +164,7 @@ public class CompileStepBeforeRun extends BeforeRunTaskProvider<CompileStepBefor
runConfiguration.getClass().getName());
}
}
projectTask = projectTaskManager.createModulesBuildTask(true, modules);
projectTask = projectTaskManager.createModulesBuildTask(modules, true, true, true);
}
else {
projectTask = projectTaskManager.createAllModulesBuildTask(true, myProject);
@@ -65,9 +65,11 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass {
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
@@ -226,6 +228,12 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass {
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;
@@ -34,8 +34,10 @@ import org.jetbrains.annotations.Nullable;
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
@@ -57,24 +57,20 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
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);
}
@@ -24,6 +24,7 @@ import com.intellij.codeInspection.reference.*;
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;
@@ -246,7 +247,7 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT
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>"),
@@ -401,12 +401,10 @@ public class DuplicatesFinder {
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;
@@ -15,7 +15,8 @@
*/
package com.intellij.codeInsight.daemon.impl;
import com.intellij.openapi.util.Couple;
import com.intellij.codeInsight.hints.filtering.Matcher;
import com.intellij.codeInsight.hints.filtering.MatcherConstructor;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.TypeConversionUtil;
@@ -26,22 +27,25 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.intellij.openapi.util.text.StringUtil.containsIgnoreCase;
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
public class ParameterNameHintsManager {
private static final List<Couple<String>> COMMONLY_USED_PARAMETER_PAIR = ContainerUtil.newArrayList(
Couple.of("begin", "end"),
Couple.of("start", "end"),
Couple.of("first", "last"),
Couple.of("first", "second"),
Couple.of("from", "to"),
Couple.of("key", "value"),
Couple.of("min", "max"),
Couple.of("format", "arg")
);
private static List<Matcher> MATCHERS = Stream.of(
"(begin*, end*)",
"(start*, end*)",
"(first*, last*)",
"(first*, second*)",
"(from*, to*)",
"(min*, max*)",
"(key, value)",
"(format, arg)"
).map((s) -> MatcherConstructor.INSTANCE.createMatcher(s))
.collect(Collectors.toList());
private static final Set<String> COMMON_METHOD_NAMES = ContainerUtil.newHashSet("set", "print", "println");
@NotNull
@@ -173,7 +177,7 @@ public class ParameterNameHintsManager {
final int totalDescriptors = descriptors.size();
if (totalDescriptors == 1 && shouldIgnoreSingleHint(parameters, descriptors)
|| totalDescriptors == 2 && parameters.length == 2 && isParamPairToIgnore(descriptors.get(0), descriptors.get(1)))
|| totalDescriptors == 2 && parameters.length == 2 && isParamPairToIgnore(descriptors))
{
return ContainerUtil.emptyList();
}
@@ -206,18 +210,13 @@ public class ParameterNameHintsManager {
return new InlayInfo(paramName, callArgument.getTextRange().getStartOffset(), callArgument);
}
private static boolean isParamPairToIgnore(InlayInfo first, InlayInfo second) {
String firstParamName = first.getText();
String secondParamName = second.getText();
private static boolean isParamPairToIgnore(List<InlayInfo> descriptors) {
List<String> params = descriptors
.stream()
.map((e) -> e.getText())
.collect(Collectors.toList());
for (Couple<String> knownPair : COMMONLY_USED_PARAMETER_PAIR) {
if (containsIgnoreCase(firstParamName, knownPair.first)
&& containsIgnoreCase(secondParamName, knownPair.second)) {
return true;
}
}
return false;
return MATCHERS.stream().anyMatch((e) -> e.isMatching("", params));
}
private static boolean shouldInlineParameterName(@NotNull PsiExpression argument,
@@ -19,18 +19,16 @@ import com.intellij.codeInsight.FileModificationService;
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.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.controlFlow.*;
import com.intellij.psi.util.PsiTreeUtil;
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;
@@ -49,65 +47,61 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
@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));
}
}
@@ -117,34 +111,26 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
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());
}
@@ -158,7 +144,7 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
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();
@@ -167,4 +153,16 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
statement.delete();
}
}
static boolean isReachable(PsiReturnStatement target) {
ControlFlow flow;
try {
flow = ControlFlowFactory.getInstance(target.getProject())
.getControlFlow(target.getParent(), LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance());
}
catch (AnalysisCanceledException e) {
return true;
}
return ControlFlowUtil.isInstructionReachable(flow, flow.getStartOffset(target), 0);
}
}
@@ -15,8 +15,8 @@
*/
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;
@@ -58,42 +58,41 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
@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) {
@@ -113,7 +112,7 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
}
PsiElement result =
toArrayExpression.replace(elementFactory.createExpressionFromText(builder.toString(), toArrayExpression));
removeLoop(foreachStatement);
removeLoop(loopStatement);
if(status != InitializerUsageStatus.AT_WANTED_PLACE) {
variable.delete();
}
@@ -121,7 +120,7 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
}
}
}
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(")");
@@ -130,7 +129,7 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
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() + "." : "";
@@ -147,7 +146,7 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
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) {
@@ -15,7 +15,6 @@
*/
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;
@@ -33,18 +32,15 @@ class ReplaceWithCountFix extends MigrateToStreamFix {
@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);
}
}
@@ -16,10 +16,10 @@
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.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.siyeh.ig.psiutils.ExpressionUtils;
import org.jetbrains.annotations.NotNull;
@@ -36,28 +36,29 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
@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);
boolean sibling = nextReturnStatement.getParent() == loopStatement.getParent();
PsiElement replacement = loopStatement.replace(elementFactory.createStatementFromText("return " + stream + ";", loopStatement));
if(sibling || !isReachable(nextReturnStatement)) {
nextReturnStatement.delete();
}
return foreachStatement.replace(elementFactory.createStatementFromText("return " + stream + ";", foreachStatement));
return replacement;
}
else {
PsiStatement[] statements = tb.getStatements();
@@ -66,9 +67,9 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
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;
@@ -77,17 +78,28 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
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));
PsiAssignmentExpression previousAssignment =
ExpressionUtils.getAssignment(PsiTreeUtil.skipSiblingsBackward(loopStatement, PsiWhiteSpace.class, PsiComment.class));
if(previousAssignment != null) {
PsiExpression prevRValue = previousAssignment.getRExpression();
PsiExpression prevLValue = previousAssignment.getLExpression();
if(prevRValue != null && prevLValue instanceof PsiReferenceExpression && ((PsiReferenceExpression)prevLValue).resolve() == var) {
previousAssignment.delete();
return loopStatement.replace(elementFactory.createStatementFromText(
var.getName() + " = " + generateOptionalUnwrap(stream, tb, value, prevRValue, var.getType()) + ";", loopStatement));
}
}
return loopStatement.replace(elementFactory.createStatementFromText(
var.getName() + " = " + generateOptionalUnwrap(stream, tb, value, lValue, var.getType()) + ";", loopStatement));
}
}
@@ -15,7 +15,6 @@
*/
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.*;
@@ -41,24 +40,22 @@ class ReplaceWithForeachCallFix extends MigrateToStreamFix {
@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());
@@ -15,7 +15,6 @@
*/
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;
@@ -46,74 +45,78 @@ class ReplaceWithMatchFix extends MigrateToStreamFix {
@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));
PsiElement result = loopStatement.replace(elementFactory.createStatementFromText("return " + streamText + ";", loopStatement));
if(!isReachable(nextReturnStatement)) {
nextReturnStatement.delete();
}
return result;
}
}
}
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) {
PsiExpression lValue = assignment.getLExpression();
PsiExpression rValue = assignment.getRExpression();
if (!(lValue instanceof PsiReferenceExpression) || rValue == null) return null;
PsiElement maybeVar = ((PsiReferenceExpression)lValue).resolve();
if(maybeVar instanceof PsiVariable) {
// Simplify single assignments like this:
// boolean flag = false;
// for(....) if(...) {flag = true; break;}
PsiVariable var = (PsiVariable)maybeVar;
PsiExpression initializer = var.getInitializer();
InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
if(initializer != null && status != InitializerUsageStatus.UNKNOWN) {
String replacement;
if(ExpressionUtils.isLiteral(initializer, Boolean.FALSE) &&
ExpressionUtils.isLiteral(rValue, Boolean.TRUE)) {
replacement = streamText;
} else if(ExpressionUtils.isLiteral(initializer, Boolean.TRUE) &&
ExpressionUtils.isLiteral(rValue, Boolean.FALSE)) {
replacement = "!"+streamText;
} else {
replacement = streamText + "?" + rValue.getText() + ":" + initializer.getText();
if ((lValue instanceof PsiReferenceExpression) && rValue != null) {
PsiElement maybeVar = ((PsiReferenceExpression)lValue).resolve();
if (maybeVar instanceof PsiVariable) {
// Simplify single assignments like this:
// boolean flag = false;
// for(....) if(...) {flag = true; break;}
PsiVariable var = (PsiVariable)maybeVar;
PsiExpression initializer = var.getInitializer();
InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, loopStatement);
if (initializer != null && status != InitializerUsageStatus.UNKNOWN) {
String replacement;
if (ExpressionUtils.isLiteral(initializer, Boolean.FALSE) &&
ExpressionUtils.isLiteral(rValue, Boolean.TRUE)) {
replacement = streamText;
}
else if (ExpressionUtils.isLiteral(initializer, Boolean.TRUE) &&
ExpressionUtils.isLiteral(rValue, Boolean.FALSE)) {
replacement = "!" + streamText;
}
else {
replacement = streamText + "?" + rValue.getText() + ":" + initializer.getText();
}
return replaceInitializer(loopStatement, var, initializer, replacement, status);
}
return replaceInitializer(foreachStatement, 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,
@@ -15,7 +15,7 @@
*/
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;
@@ -33,11 +33,9 @@ class ReplaceWithSumFix extends MigrateToStreamFix {
@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);
@@ -50,9 +48,8 @@ class ReplaceWithSumFix extends MigrateToStreamFix {
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);
}
}
@@ -32,6 +32,7 @@ import com.intellij.psi.controlFlow.*;
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;
@@ -43,6 +44,7 @@ import com.intellij.util.containers.IntArrayList;
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;
@@ -123,7 +125,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
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;
}
@@ -350,7 +352,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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,
@@ -385,6 +390,27 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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) {
@@ -465,26 +491,22 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
@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;
@@ -502,7 +524,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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) {
@@ -514,8 +536,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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";
@@ -535,7 +557,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
// 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()
@@ -548,8 +570,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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;
@@ -561,7 +583,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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;
}
@@ -583,14 +605,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
}
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);
@@ -616,7 +638,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
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())
@@ -625,13 +650,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
}
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) {
@@ -643,18 +663,28 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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);
}
@@ -700,7 +730,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
@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;
@@ -799,7 +829,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
return StreamEx.of(myExpression);
}
abstract String createReplacement(PsiElementFactory factory);
abstract String createReplacement();
}
static class FilterOp extends Operation {
@@ -815,7 +845,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
@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;
@@ -858,7 +889,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
@Override
public String createReplacement(PsiElementFactory factory) {
public String createReplacement() {
if (isIdentityMapping(myVariable, myExpression)) {
if (!(myType instanceof PsiPrimitiveType)) {
return myVariable.getType() instanceof PsiPrimitiveType ? ".boxed()" : "";
@@ -894,20 +925,33 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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) {
@@ -915,35 +959,155 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
}
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);
}
}
/**
@@ -952,11 +1116,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
* 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) {
@@ -1052,46 +1217,32 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
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));
}
}
}
@@ -1121,7 +1272,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
return null;
}
@Nullable
@NotNull
public Operation getLastOperation() {
return myPreviousOp;
}
@@ -1141,7 +1292,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
public boolean hasOperations() {
return myPreviousOp != null;
return !(myPreviousOp instanceof StreamSource);
}
public boolean isEmpty() {
@@ -1163,6 +1314,13 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
* @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);
}
@@ -1184,8 +1342,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
@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();
}
}
}
@@ -107,16 +107,15 @@ public class JavadocHelper {
}
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);
}
@@ -169,9 +169,9 @@ public class InferenceSession {
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,
@@ -382,7 +382,6 @@ public class InferenceSession {
final Ref<String> errorMessage = new Ref<String>();
final PsiType targetType = getTargetTypeFromParent(parent, errorMessage, false);
if (targetType == null && errorMessage.get() != null) {
registerIncompatibleErrorMessage(errorMessage.get());
return;
}
@@ -393,6 +392,7 @@ public class InferenceSession {
}
if (!repeatInferencePhases()) {
resolveBounds(getInputInferenceVariablesFromTopLevelFunctionalExpressions(args, properties), initialSubstitutor);
return;
}
@@ -405,34 +405,37 @@ public class InferenceSession {
}
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() {
@@ -1106,8 +1109,8 @@ public class InferenceSession {
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);
@@ -1132,15 +1135,36 @@ public class InferenceSession {
}
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) {
@@ -138,7 +138,7 @@ public class InferenceSessionContainer {
}
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);
}
@@ -51,7 +51,7 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
}
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);
@@ -3,8 +3,8 @@ import java.util.*;
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,
@@ -57,7 +57,7 @@ class ReturnTypeCompatibility {
}
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;});
}
}
@@ -0,0 +1,21 @@
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
class A {
{
run(A.class, this, (o) -> {
o.meth();
<error descr="Missing return statement">}</error>);
Map<Integer, Integer> map = Stream.iterate(5, <error descr="no instance(s) of type variable(s) T exist so that Stream<T> conforms to Map<Integer, Integer>">t -> t + 5</error>);
}
void meth() {}
<T> T run(Class<T> c, T t, Function<T, T> f) {
return f.apply(t);
}
}
@@ -0,0 +1,12 @@
// "Replace with anyMatch()" "true"
import java.util.List;
public class Main {
public void testAssignment(List<String> data) {
String[] found = {"no"};
if (data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty())) {
found[0] = "yes";
}
}
}
@@ -0,0 +1,13 @@
// "Replace with anyMatch()" "true"
import java.util.List;
public class Main {
boolean find(List<String> data) {
if(data != null) {
return data.stream().map(String::trim).anyMatch(trimmed -> trimmed.startsWith("xyz"));
} else {
throw new IllegalArgumentException();
}
}
}
@@ -0,0 +1,20 @@
// "Replace with findFirst()" "true"
import java.util.List;
import java.util.Map;
import java.util.Objects;
public class Main {
private int getInitialSize() {return 0;}
public void testMap(Map<String, List<String>> map) throws Exception {
int firstSize = 10;
System.out.println(firstSize);
// loop
// comment
firstSize = map.values().stream().filter(Objects::nonNull).findFirst().map(List::size).orElse(getInitialSize());
System.out.println(firstSize);
}
}
@@ -0,0 +1,15 @@
// "Replace with findFirst()" "true"
import java.util.Collection;
import java.util.List;
public class Main {
public static String find(List<List<String>> list) {
if(list == null) {
System.out.println("oops");
return "";
} else {
return list.stream().flatMap(Collection::stream).filter(string -> string.startsWith("ABC")).findFirst().orElse(null);
}
}
}
@@ -0,0 +1,11 @@
// "Replace with findFirst()" "true"
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
public class Main {
public String testNestedForLoop(int[] data, List<String> info) {
return Arrays.stream(data).flatMap(val -> IntStream.rangeClosed(0, val)).mapToObj(info::get).filter(str -> !str.isEmpty()).findFirst().orElse(null);
}
}
@@ -0,0 +1,12 @@
// "Replace with collect" "true"
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result = IntStream.range(0, 10).mapToObj(i -> input.get(i).length()).collect(Collectors.toList());
}
}
@@ -0,0 +1,12 @@
// "Replace with collect" "true"
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
public void testForLoop() {
List<Integer> result = IntStream.rangeClosed(0, 10).boxed().collect(Collectors.toList());
}
}
@@ -0,0 +1,14 @@
// "Replace with collect" "true"
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result;
short s = (short)input.size();
result = IntStream.range(0, s).mapToObj(i -> input.get(i).length()).collect(Collectors.toList());
}
}
@@ -0,0 +1,8 @@
import java.util.Arrays;
// "Replace with forEach" "true"
public class Main {
public void test(int[] arr) {
Arrays.stream(arr).filter(i -> i > 0).forEach(System.out::println);
}
}
@@ -0,0 +1,16 @@
// "Replace with anyMatch()" "true"
import java.util.List;
public class Main {
public void testAssignment(List<String> data) {
String[] found = {"no"};
for(String str : da<caret>ta) {
String trimmed = str.trim();
if(!trimmed.isEmpty()) {
found[0] = "yes";
break;
}
}
}
}
@@ -0,0 +1,19 @@
// "Replace with anyMatch()" "true"
import java.util.List;
public class Main {
boolean find(List<String> data) {
if(data != null) {
for (String e : da<caret>ta) {
String trimmed = e.trim();
if (trimmed.startsWith("xyz")) {
return true;
}
}
} else {
throw new IllegalArgumentException();
}
return false;
}
}
@@ -0,0 +1,25 @@
// "Replace with findFirst()" "true"
import java.util.List;
import java.util.Map;
public class Main {
private int getInitialSize() {return 0;}
public void testMap(Map<String, List<String>> map) throws Exception {
int firstSize = 10;
System.out.println(firstSize);
firstSize = getInitialSize();
// loop
for(List<String> list : map.valu<caret>es()) {
if(list != null) {
firstSize = list.size();
// comment
break;
}
}
System.out.println(firstSize);
}
}
@@ -0,0 +1,21 @@
// "Replace with findFirst()" "true"
import java.util.List;
public class Main {
public static String find(List<List<String>> list) {
if(list == null) {
System.out.println("oops");
return "";
} else {
for (List<String> innerList : lis<caret>t) {
for (String string : innerList) {
if (string.startsWith("ABC")) {
return string;
}
}
}
}
return null;
}
}
@@ -0,0 +1,18 @@
// "Replace with findFirst()" "false"
public class Main {
public boolean check(int value) {
return value == 3;
}
public void find() {
int end = 10;
for(<caret>int i=0; i<end; i++) {
if(check(i)) {
end = i;
break;
}
}
System.out.println(end);
}
}
@@ -0,0 +1,17 @@
// "Replace with findFirst()" "true"
import java.util.List;
public class Main {
public String testNestedForLoop(int[] data, List<String> info) {
for(int val : da<caret>ta) {
for(int x = 0; x <= val; x++) {
String str = info.get(x);
if(!str.isEmpty()) {
return str;
}
}
}
return null;
}
}
@@ -0,0 +1,13 @@
// "Replace with collect" "true"
import java.util.ArrayList;
import java.util.List;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result = new ArrayList<>();
for (in<caret>t i = 0; i < 10; i++) {
result.add(input.get(i).length());
}
}
}
@@ -0,0 +1,13 @@
// "Replace with collect" "true"
import java.util.ArrayList;
import java.util.List;
public class Main {
public void testForLoop() {
List<Integer> result = new ArrayList<>();
for (in<caret>t i = 0; 10 >= i; i++) {
result.add(i);
}
}
}
@@ -0,0 +1,14 @@
// "Replace with collect" "false"
import java.util.ArrayList;
import java.util.List;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result = new ArrayList<>();
float s = (float)input.size();
for (in<caret>t i = 0; i < s; i++) {
result.add(input.get(i).length());
}
}
}
@@ -0,0 +1,14 @@
// "Replace with collect" "true"
import java.util.ArrayList;
import java.util.List;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result = new ArrayList<>();
short s = (short)input.size();
for (in<caret>t i = 0; i < s; i++) {
result.add(input.get(i).length());
}
}
}
@@ -0,0 +1,13 @@
// "Replace with collect" "false"
import java.util.ArrayList;
import java.util.List;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result = new ArrayList<>();
for (in<caret>t i = 0; i < 10; i++) {
result.add(input.get(i++).length());
}
}
}
@@ -0,0 +1,13 @@
// "Replace with collect" "false"
import java.util.ArrayList;
import java.util.List;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result = new ArrayList<>();
for (in<caret>t i = 0; i > 10; i++) {
result.add(input.get(i).length());
}
}
}
@@ -0,0 +1,13 @@
// "Replace with collect" "false"
import java.util.ArrayList;
import java.util.List;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result = new ArrayList<>();
for (in<caret>t i = 0; i < 10; i+=2) {
result.add(input.get(i).length());
}
}
}
@@ -0,0 +1,13 @@
// "Replace with collect" "false"
import java.util.ArrayList;
import java.util.List;
public class Main {
public void testForLoop(List<String> input) {
List<Integer> result = new ArrayList<>();
for (in<caret>t i = 0, j=0; i < 10; i++) {
result.add(input.get(i).length());
}
}
}
@@ -1,7 +1,7 @@
// "Replace with forEach" "false"
// "Replace with forEach" "true"
public class Main {
public void test(int[] arr) {
for(int i : arr) {
for(int i : a<caret>rr) {
if(i > 0) {
System.out.println(i);
}
@@ -0,0 +1,10 @@
// "Replace with forEach" "false"
public class Main {
public void test(int[] arr) {
for(float i : a<caret>rr) {
if(i > 0) {
System.out.println(i);
}
}
}
}
@@ -0,0 +1,18 @@
// "Replace with sum()" "false"
import java.util.List;
public class Main {
public long testFor(List<List<String>> list) {
long count = 0;
for (int i = 0; i < list.size(); i++) {
for (String s : list.g<caret>et(i)) {
String trimmed = s.trim();
if (trimmed.isEmpty()) {
count += i;
}
}
}
return count;
}
}
@@ -187,7 +187,7 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
}
public void testAcceptInferredVariablesBeforeAdditionalConstraintsLeadToFail() throws Exception {
doTest(false);
doTest();
}
public void testEnsureNoCaptureIsPerformedOverTargetTypeOfCastExpressionWhichMarksFunctionalExpression() throws Exception {
@@ -335,13 +335,13 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
private void doTest() {
doTest(false);
public void testInferTypeParametersFromFunctionalInterfaceInputs() throws Exception {
doTest();
}
private void doTest(boolean warnings) {
private void doTest() {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
}
/*
@@ -95,7 +95,7 @@ class Test {
expected: '''\
class Test {
/**
* @param i <caret>
* @param i <caret>
* @param j
*/
void test(int i, int j) {
@@ -251,7 +251,7 @@ class Test {
expected: '''\
class Test {
/**
* @param i <caret>
* @param i <caret>
*/
void test(int i) {
}
@@ -272,7 +272,7 @@ class Test {
expected: '''\
class Test {
/**
* @param i <caret>
* @param i <caret>
* @param j
* @param k
*/
@@ -399,7 +399,7 @@ class Test<T> {<caret>
/**
* My description
* @author me
* @param <T> <caret>
* @param <T> <caret>
*/
class Test<T> {
}''')
@@ -420,7 +420,7 @@ class Test<T, V> {
* My description
* @author me
* @param <T> type description
* @param <V> <caret>
* @param <V> <caret>
*/
class Test<T, V> {
}''')
@@ -467,7 +467,7 @@ class Test {
expected: '''\
class Test {
/**
* @param i <caret>
* @param i <caret>
* @param j
*/
public void test(int i, int j) {
@@ -491,7 +491,7 @@ class Test {
class Test {
/**
* @param <A> A description
* @param <B> <caret>
* @param <B> <caret>
*/
<A, B> void test() {
}
@@ -515,7 +515,7 @@ class Test<A, B> {<caret>
/**
* Class description
* @author Zigmund
* @param <A> <caret>
* @param <A> <caret>
* @param <B> multi-line
* description
*/
@@ -575,7 +575,7 @@ class Test {
expected: '''\
class Test {
/**
* @param i <caret>
* @param i <caret>
*/
void test(int i) {
}
@@ -712,16 +712,20 @@ public class DirectoryIndexTest extends IdeaTestCase {
assertIteratedContent(myFileIndex, Arrays.asList(fileSourceRoot, fileTestSourceRoot), Collections.singletonList(fileRoot));
}
private static void assertIteratedContent(ProjectFileIndex fileIndex,
private void assertIteratedContent(Module module, @Nullable List<VirtualFile> contains, @Nullable List<VirtualFile> doesntContain) {
assertIteratedContent(ModuleRootManager.getInstance(module).getFileIndex(), contains, doesntContain);
assertIteratedContent(myFileIndex, contains, doesntContain);
}
private static void assertIteratedContent(FileIndex fileIndex,
@Nullable List<VirtualFile> contains,
@Nullable List<VirtualFile> doesntContain) {
final Set<VirtualFile> collected = new THashSet<>();
fileIndex.iterateContent(new ContentIterator() {
@Override
public boolean processFile(VirtualFile fileOrDir) {
collected.add(fileOrDir);
return true;
fileIndex.iterateContent(fileOrDir -> {
if (!collected.add(fileOrDir)) {
fail(fileOrDir + " visited twice");
}
return true;
});
if (contains != null) assertContainsElements(collected, contains);
if (doesntContain != null) assertDoesntContain(collected, doesntContain);
@@ -856,10 +860,61 @@ public class DirectoryIndexTest extends IdeaTestCase {
assertTrue(myFileIndex.isInSource(fileSourceRoot));
}
public void testContentRootUnderExcludedRoot() {
VirtualFile dirUnderExcluded = createChildDirectory(myExcludeDir, "generated");
PsiTestUtil.addSourceContentToRoots(myModule2, dirUnderExcluded);
checkInfo(dirUnderExcluded, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
public void testSourceContentRootsUnderExcludedRoot() {
VirtualFile contentRoot = createChildDirectory(myExcludeDir, "content");
PsiTestUtil.addContentRoot(myModule2, contentRoot);
checkInfo(contentRoot, myModule2, false, false, null, null, myModule2, myModule3);
VirtualFile excludedFile = createChildData(myExcludeDir, "excluded.txt");
VirtualFile sourceRoot = createChildDirectory(myExcludeDir, "src");
VirtualFile sourceFile = createChildData(sourceRoot, "source.txt");
PsiTestUtil.addSourceRoot(myModule2, sourceRoot);
assertEquals(myModule2Dir, assertInProject(sourceRoot).getContentRoot());
checkInfo(sourceRoot, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
VirtualFile contentSourceRoot = createChildDirectory(myExcludeDir, "content-src");
VirtualFile contentSourceFile = createChildData(sourceRoot, "content-source.txt");
PsiTestUtil.addSourceContentToRoots(myModule2, contentSourceRoot);
checkInfo(contentSourceRoot, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
assertIteratedContent(myModule2, Arrays.asList(sourceFile, contentSourceFile, sourceRoot, contentSourceRoot),
Arrays.asList(excludedFile, myExcludeDir));
}
public void testSourceContentRootsUnderExcludedRootUnderSourceRoot() {
VirtualFile excluded = createChildDirectory(myModule2Dir, "excluded");
PsiTestUtil.addExcludedRoot(myModule2, excluded);
VirtualFile excludedFile = createChildData(excluded, "excluded.txt");
VirtualFile contentRoot = createChildDirectory(excluded, "content");
PsiTestUtil.addContentRoot(myModule2, contentRoot);
checkInfo(contentRoot, myModule2, false, false, null, null);
VirtualFile sourceRoot = createChildDirectory(excluded, "src");
PsiTestUtil.addSourceRoot(myModule2, sourceRoot);
VirtualFile sourceFile = createChildData(sourceRoot, "source.txt");
assertEquals(myModule2Dir, assertInProject(sourceRoot).getContentRoot());
checkInfo(sourceRoot, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
VirtualFile contentSourceRoot = createChildDirectory(excluded, "content-src");
VirtualFile contentSourceFile = createChildData(contentSourceRoot, "content-source.txt");
PsiTestUtil.addSourceContentToRoots(myModule2, contentSourceRoot);
checkInfo(contentSourceRoot, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
assertIteratedContent(myModule2, Arrays.asList(sourceFile, contentSourceFile, sourceRoot, contentSourceRoot),
Arrays.asList(excludedFile, myExcludeDir));
}
public void testExcludedSourceRootUnderExcluded() {
VirtualFile excluded = createChildDirectory(myModule2Dir, "excluded");
PsiTestUtil.addExcludedRoot(myModule2, excluded);
VirtualFile src = createChildDirectory(excluded, "src");
VirtualFile sourceFile = createChildData(src, "src.txt");
PsiTestUtil.addSourceRoot(myModule2, src);
PsiTestUtil.addExcludedRoot(myModule2, src);
assertExcluded(src, myModule2);
assertIteratedContent(myModule2, null, Arrays.asList(sourceFile));
}
private void checkInfo(VirtualFile file,
@@ -142,20 +142,44 @@ public class ProjectTreeStructureTest extends BaseProjectViewTestCase {
ModuleManagerImpl.getInstanceImpl(myProject).setModuleGroupPath(module, new String[]{"modules"});
PsiTestUtil.addContentRoot(module, mainModuleRoot.findFileByRelativePath("src/com/package1/p2/p3"));
TestProjectTreeStructure structure = new TestProjectTreeStructure(myProject, getTestRootDisposable());
structure.setShowLibraryContents(false);
myStructure.setShowLibraryContents(false);
myStructure.hideExcludedFiles();
String structureContent = PlatformTestUtil.print(structure, structure.getRootElement(), 0, null, 10, ' ', myPrintInfo).toString();
assertStructureEqual("Project\n" +
" nested_module.iml\n" +
" noDuplicateModules\n" +
" src\n" +
" com\n" +
" package1\n" +
" Test.java\n" +
" testNoDuplicateModules.iml\n");
}
Assert.assertFalse(structureContent.contains("modules"));
assertEquals("Project\n" +
" noDuplicateModules\n" +
" src\n" +
" com\n" +
" package1\n" +
" Test.java\n" +
" nested_module.iml\n" +
" testNoDuplicateModules.iml\n",
structureContent);
public void testContentRootUnderExcluded() {
VirtualFile mainModuleRoot = ModuleRootManager.getInstance(myModule).getContentRoots()[0];
PsiTestUtil.addExcludedRoot(myModule, mainModuleRoot.findFileByRelativePath("exc"));
PsiTestUtil.addContentRoot(myModule, mainModuleRoot.findFileByRelativePath("exc/gen"));
myStructure.setShowLibraryContents(false);
assertStructureEqual("Project\n" +
" contentRootUnderExcluded\n" +
" B.txt\n" +
" exc\n" +
" excluded.txt\n" +
" gen\n" +
" A.java\n" +
" testContentRootUnderExcluded.iml\n");
myStructure.hideExcludedFiles();
assertStructureEqual("Project\n" +
" Module\n" +
" contentRootUnderExcluded\n" +
" B.txt\n" +
" gen\n" +
" A.java\n" +
" testContentRootUnderExcluded.iml\n");
}
}
@@ -65,9 +65,17 @@ public abstract class BaseProjectViewTestCase extends TestSourceBasedTestCase {
return myStructure;
}
private void assertStructureEqual(PsiDirectory root, String expected, int maxRowCount, AbstractTreeStructure structure) {
private void assertStructureEqual(PsiDirectory root, String expected, int maxRowCount, AbstractProjectTreeStructure structure) {
assertNotNull(root);
PsiDirectoryNode rootNode = new PsiDirectoryNode(myProject, root, (ViewSettings)structure);
PsiDirectoryNode rootNode = new PsiDirectoryNode(myProject, root, structure);
assertStructureEqual(expected, maxRowCount, rootNode);
}
protected void assertStructureEqual(String expected) {
assertStructureEqual(expected, -1, myStructure.getRootElement());
}
private void assertStructureEqual(String expected, int maxRowCount, Object rootNode) {
ProjectViewTestUtil.assertStructureEqual(myStructure, expected, maxRowCount, PlatformTestUtil.createComparator(myPrintInfo), rootNode, myPrintInfo);
}
@@ -22,6 +22,10 @@ import org.jetbrains.jps.model.artifact.JpsArtifact;
import java.util.List;
/**
* Allows to perform additional tasks when artifacts are built. Implementations of this class are registered as Java services, by creating
* a file META-INF/services/org.jetbrains.jps.builders.artifacts.ArtifactBuildTaskProvider containing the qualified name of your
* implementation class.
*
* @author nik
*/
public abstract class ArtifactBuildTaskProvider {
@@ -38,6 +42,13 @@ public abstract class ArtifactBuildTaskProvider {
}
}
/**
* Returns list of tasks which need to be executed during {@code buildPhase} when {@code artifact} is building. Firstly tasks returned for
* {@link ArtifactBuildPhase#PRE_PROCESSING PRE_PROCESSING} are executed, then files specified in the artifact layout are copied to the output directory.
* If all files in the artifact output were up to date, i.e. no copying was performed, the build finishes. Otherwise all tasks returned for
* {@link ArtifactBuildPhase#FINISHING_BUILD FINISHING_BUILD} are executed and then all tasks returned for
* {@link ArtifactBuildPhase#POST_PROCESSING POST_PROCESSING} are executed.
*/
@NotNull
public abstract List<? extends BuildTask> createArtifactBuildTasks(@NotNull JpsArtifact artifact, @NotNull ArtifactBuildPhase buildPhase);
}
@@ -26,6 +26,7 @@ import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.JpsJavaModuleExtension;
import org.jetbrains.jps.model.java.JpsJavaProjectExtension;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
import org.jetbrains.jps.util.JpsPathUtil;
import java.io.File;
@@ -67,6 +68,11 @@ public class ModuleExcludeIndexImpl implements ModuleExcludeIndex {
moduleContent.add(contentRoot);
contentToModule.put(contentRoot, module);
}
for (JpsModuleSourceRoot root : module.getSourceRoots()) {
File sourceRoot = root.getFile();
moduleContent.add(sourceRoot);
contentToModule.put(sourceRoot, module);
}
myModuleToExcludesMap.put(module, moduleExcludes);
myModuleToContentMap.put(module, moduleContent);
myExcludedRoots.addAll(moduleExcludes);
@@ -0,0 +1,3 @@
class B {
A a;
}
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/exc/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/exc" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/sourceRootUnderExcluded.iml" filepath="$PROJECT_DIR$/sourceRootUnderExcluded.iml" />
</modules>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
@@ -0,0 +1,3 @@
class A {
B b;
}
@@ -69,6 +69,17 @@ class ModuleRebuildTest: JpsRebuildTestCase() {
})
}
fun testSourceRootUnderExcluded() {
doTest("sourceRootUnderExcluded/sourceRootUnderExcluded.ipr", fs {
dir("production") {
dir("sourceRootUnderExcluded") {
file("A.class")
file("B.class")
}
}
})
}
fun testResourceCopying() {
doTest("resourceCopying/resourceCopying.ipr", fs {
dir("production") {
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.indices.impl.ModuleExcludeIndexImpl;
import org.jetbrains.jps.model.JpsJavaModelTestCase;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import org.jetbrains.jps.model.java.JpsJavaModuleExtension;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.util.JpsPathUtil;
@@ -138,6 +139,24 @@ public class ModuleExcludeIndexTest extends JpsJavaModelTestCase {
assertFalse(index.isExcludedFromModule(innerRoot, inner));
}
public void testSourceRootUnderExcluded() {
File project = new File(myRoot, "project");
File exc = new File(project, "exc");
File src = new File(exc, "src");
JpsModule module = addModule();
addContentRoot(module, project);
addExcludedRoot(module, exc);
addSourceRoot(module, src);
assertNotExcluded(src);
addExcludedRoot(module, src);
assertExcluded(src);
}
private static void addSourceRoot(JpsModule module, File src) {
module.addSourceRoot(JpsPathUtil.pathToUrl(src.getAbsolutePath()), JavaSourceRootType.SOURCE);
}
private static void addExcludedRoot(JpsModule module, File root) {
module.getExcludeRootsList().addUrl(JpsPathUtil.pathToUrl(root.getAbsolutePath()));
}
@@ -1,3 +1,18 @@
/*
* Copyright 2000-2016 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.jetbrains.jsonSchema.impl;
import com.intellij.json.psi.*;
@@ -244,7 +259,8 @@ class JsonBySchemaObjectAnnotator implements Annotator {
}
private boolean checkForEnum(JsonValue value, JsonSchemaObject schema) {
if (schema.getEnum() == null) return true;
//enum values + pattern -> don't check enum values
if (schema.getEnum() == null || schema.getPattern() != null) return true;
final String text = value.getText();
final List<Object> objects = schema.getEnum();
for (Object object : objects) {
@@ -26,8 +26,10 @@ import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class RefDirectoryImpl extends RefElementImpl implements RefDirectory{
private RefModule myRefModule;
protected RefDirectoryImpl(PsiDirectory psiElement, RefManager refManager) {
super(psiElement.getName(), psiElement, refManager);
final PsiDirectory parentDirectory = psiElement.getParentDirectory();
@@ -38,13 +40,10 @@ public class RefDirectoryImpl extends RefElementImpl implements RefDirectory{
return;
}
}
final Module module = ModuleUtilCore.findModuleForPsiElement(psiElement);
if (module != null) {
final RefModuleImpl refModule = (RefModuleImpl)refManager.getRefModule(module);
if (refModule != null) {
refModule.add(this);
return;
}
myRefModule = refManager.getRefModule(ModuleUtilCore.findModuleForPsiElement(psiElement));
if (myRefModule != null) {
((RefModuleImpl)myRefModule).add(this);
return;
}
((RefProjectImpl)refManager.getRefProject()).add(this);
}
@@ -54,6 +53,12 @@ public class RefDirectoryImpl extends RefElementImpl implements RefDirectory{
ApplicationManager.getApplication().runReadAction(() -> visitor.visitDirectory(this));
}
@Nullable
@Override
public RefModule getModule() {
return myRefModule;
}
@Override
protected void initialize() {
}
@@ -61,14 +61,12 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement
private String[] mySuppressions = null;
private boolean myIsDeleted ;
private final Module myModule;
protected static final int IS_REACHABLE_MASK = 0x40;
protected RefElementImpl(@NotNull String name, @NotNull RefElement owner) {
super(name, owner.getRefManager());
myID = null;
myFlags = 0;
myModule = ModuleUtilCore.findModuleForPsiElement(owner.getElement());
}
protected RefElementImpl(PsiFile file, RefManager manager) {
@@ -79,7 +77,6 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement
super(name, manager);
myID = SmartPointerManager.getInstance(manager.getProject()).createSmartPsiElementPointer(element);
myFlags = 0;
myModule = ModuleUtilCore.findModuleForPsiElement(element);
}
@Override
@@ -114,7 +111,8 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement
@Override
public RefModule getModule() {
return myManager.getRefModule(myModule);
final RefEntity owner = getOwner();
return owner instanceof RefElement ? ((RefElement)owner).getModule() : null;
}
@Override
@@ -21,15 +21,14 @@ import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.util.JDOMExternalizerUtil;
import com.intellij.openapi.util.NullableLazyValue;
import com.intellij.openapi.util.VolatileNullableLazyValue;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
@@ -38,7 +37,7 @@ import java.util.concurrent.ConcurrentMap;
* A type of item with a distinct highlighting in an editor or in other views.
*/
public final class TextAttributesKey implements Comparable<TextAttributesKey> {
private static final Logger LOG = Logger.getInstance("#" + TextAttributesKey.class.getName());
private static final Logger LOG = Logger.getInstance(TextAttributesKey.class);
private static final TextAttributes NULL_ATTRIBUTES = new TextAttributes();
private static final ConcurrentMap<String, TextAttributesKey> ourRegistry = ContainerUtil.newConcurrentMap();
@@ -69,7 +68,14 @@ public final class TextAttributesKey implements Comparable<TextAttributesKey> {
@NotNull
public static TextAttributesKey find(@NotNull @NonNls String externalName) {
return ConcurrencyUtil.cacheOrGet(ourRegistry, externalName, new TextAttributesKey(externalName));
TextAttributesKey v = ourRegistry.get(externalName);
if (v != null) {
return v;
}
v = new TextAttributesKey(externalName);
TextAttributesKey prev = ourRegistry.putIfAbsent(externalName, v);
return prev == null ? v : prev;
}
public String toString() {
@@ -182,14 +188,15 @@ public final class TextAttributesKey implements Comparable<TextAttributesKey> {
return key;
}
@Nullable
public TextAttributesKey getFallbackAttributeKey() {
return myFallbackAttributeKey;
}
public void setFallbackAttributeKey(TextAttributesKey fallbackAttributeKey) {
public void setFallbackAttributeKey(@Nullable TextAttributesKey fallbackAttributeKey) {
myFallbackAttributeKey = fallbackAttributeKey;
if (fallbackAttributeKey != null) {
checkDependencies(fallbackAttributeKey, new HashSet<TextAttributesKey>());
checkDependencies(fallbackAttributeKey, new THashSet<TextAttributesKey>());
}
}
@@ -204,33 +211,30 @@ public final class TextAttributesKey implements Comparable<TextAttributesKey> {
TextAttributes getDefaultAttributes(TextAttributesKey key);
}
private void checkDependencies(@Nullable TextAttributesKey key, Set<TextAttributesKey> referencedKeys) {
if (key != null) {
if (!referencedKeys.contains(key)) {
referencedKeys.add(key);
TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
if (fallbackKey != null) {
checkDependencies(fallbackKey, referencedKeys);
}
}
else {
StringBuilder sb = new StringBuilder();
sb.append("Cyclic TextAttributesKey dependency found: ");
printDependencyLoop(sb, key);
myFallbackAttributeKey = null;
LOG.error(sb.toString());
private void checkDependencies(@NotNull TextAttributesKey key, @NotNull Set<TextAttributesKey> referencedKeys) {
if (referencedKeys.add(key)) {
TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
if (fallbackKey != null) {
checkDependencies(fallbackKey, referencedKeys);
}
}
else {
StringBuilder sb = new StringBuilder();
sb.append("Cyclic TextAttributesKey dependency found: ");
printDependencyLoop(sb, key);
myFallbackAttributeKey = null;
LOG.error(sb.toString());
}
}
private void printDependencyLoop(@NotNull StringBuilder stringBuilder,
@NotNull TextAttributesKey currNode) {
private void printDependencyLoop(@NotNull StringBuilder stringBuilder, @NotNull TextAttributesKey currNode) {
stringBuilder.append(currNode.getExternalName()).append("->");
TextAttributesKey fallbackKey = currNode.getFallbackAttributeKey();
if (fallbackKey == this) {
stringBuilder.append(getExternalName());
return;
}
printDependencyLoop(stringBuilder, fallbackKey);
else if (fallbackKey != null) {
printDependencyLoop(stringBuilder, fallbackKey);
}
}
}
@@ -16,7 +16,6 @@
package com.intellij.openapi.editor.markup;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.InvalidDataException;
import org.intellij.lang.annotations.JdkConstants;
import org.jdom.Element;
import org.jetbrains.annotations.Contract;
@@ -32,8 +31,7 @@ public class TextAttributes implements Cloneable {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.markup.TextAttributes");
public static final TextAttributes ERASE_MARKER = new TextAttributes();
private boolean myEnforceEmpty;
public static final TextAttributes USE_INHERITED_MARKER = new TextAttributes();
@SuppressWarnings("NullableProblems")
@NotNull
@@ -71,9 +69,8 @@ public class TextAttributes implements Cloneable {
this(null, null, null, EffectType.BOXED, Font.PLAIN);
}
private TextAttributes(@NotNull AttributesFlyweight attributesFlyweight, boolean enforced) {
private TextAttributes(@NotNull AttributesFlyweight attributesFlyweight) {
myAttrs = attributesFlyweight;
myEnforceEmpty = enforced;
}
public TextAttributes(@NotNull Element element) {
@@ -97,14 +94,6 @@ public class TextAttributes implements Cloneable {
return getForegroundColor() == null && getBackgroundColor() == null && getEffectColor() == null && getFontType() == Font.PLAIN;
}
public boolean isFallbackEnabled() {
return isEmpty() && !myEnforceEmpty;
}
public boolean containsValue() {
return !isEmpty() || myEnforceEmpty;
}
public void reset() {
setForegroundColor(null);
setBackgroundColor(null);
@@ -179,7 +168,7 @@ public class TextAttributes implements Cloneable {
@Override
public TextAttributes clone() {
return new TextAttributes(myAttrs, myEnforceEmpty);
return new TextAttributes(myAttrs);
}
public boolean equals(Object obj) {
@@ -194,17 +183,8 @@ public class TextAttributes implements Cloneable {
return myAttrs.hashCode();
}
public void readExternal(Element element) {
try {
myAttrs = AttributesFlyweight.create(element);
}
catch (InvalidDataException e) {
throw new RuntimeException(e);
}
if (isEmpty()) {
myEnforceEmpty = true;
}
public void readExternal(@NotNull Element element) {
myAttrs = AttributesFlyweight.create(element);
}
public void writeExternal(Element element) {
@@ -216,17 +196,4 @@ public class TextAttributes implements Cloneable {
return "[" + getForegroundColor() + "," + getBackgroundColor() + "," + getFontType() + "," + getEffectType() + "," +
getEffectColor() + "," + getErrorStripeColor() + "]";
}
/**
* Enforces empty attributes instead of treating empty values as undefined.
*
* @param enforceEmpty True if empty values should be used as is (fallback is disabled).
*/
public void setEnforceEmpty(boolean enforceEmpty) {
myEnforceEmpty = enforceEmpty;
}
public boolean isEnforceEmpty() {
return myEnforceEmpty;
}
}
@@ -48,6 +48,7 @@ import java.util.List;
import static com.intellij.openapi.editor.colors.CodeInsightColors.*;
import static com.intellij.openapi.editor.colors.EditorColors.*;
import static com.intellij.openapi.editor.markup.TextAttributes.USE_INHERITED_MARKER;
import static com.intellij.openapi.util.Couple.of;
import static com.intellij.ui.ColorUtil.fromHex;
@@ -79,7 +80,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
private int myVersion = CURR_VERSION;
protected Map<ColorKey, Color> myColorsMap = ContainerUtilRt.newHashMap();
protected Map<TextAttributesKey, TextAttributes> myAttributesMap = ContainerUtilRt.newHashMap();
protected Map<TextAttributesKey, TextAttributes> myAttributesMap = new THashMap<>();
@NonNls private static final String EDITOR_FONT = "font";
@NonNls private static final String CONSOLE_FONT = "console-font";
@@ -180,7 +181,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
newScheme.setFont(type, font);
}
newScheme.myAttributesMap = new HashMap<>(myAttributesMap);
newScheme.myAttributesMap = new THashMap<>(myAttributesMap);
newScheme.myColorsMap = new HashMap<>(myColorsMap);
newScheme.myVersion = myVersion;
}
@@ -403,14 +404,16 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
public void readAttributes(@NotNull Element childNode) {
for (Element e : childNode.getChildren(OPTION_ELEMENT)) {
TextAttributesKey key = TextAttributesKey.find(e.getAttributeValue(NAME_ATTR));
Element valueElement = e.getChild(VALUE_ELEMENT);
TextAttributes attr = myValueReader.read(TextAttributes.class, valueElement);
String baseKeyName = e.getAttributeValue(BASE_ATTRIBUTES_ATTR);
if (baseKeyName != null) {
// For now inheritance overriding is not supported, just make sure that empty attributes mean inheritance.
attr.setEnforceEmpty(false);
TextAttributesKey key = TextAttributesKey.find(e.getAttributeValue(NAME_ATTR));
if (valueElement == null) {
if (e.getAttributeValue(BASE_ATTRIBUTES_ATTR) != null) {
myAttributesMap.put(key, USE_INHERITED_MARKER);
}
continue;
}
TextAttributes attr = myValueReader.read(TextAttributes.class, valueElement);
myAttributesMap.put(key, attr);
migrateErrorStripeColorFrom14(key, attr);
}
@@ -623,24 +626,54 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
private void writeAttributes(@NotNull Element attrElements) throws WriteExternalException {
List<TextAttributesKey> list = new ArrayList<>(myAttributesMap.keySet());
list.sort(null);
for (TextAttributesKey key: list) {
TextAttributes defaultAttr = myParentScheme != null ? myParentScheme.getAttributes(key) : new TextAttributes();
for (TextAttributesKey key : list) {
TextAttributes attributes = myAttributesMap.get(key);
TextAttributesKey baseKey = key.getFallbackAttributeKey();
TextAttributes defaultFallbackAttr =
baseKey != null && myParentScheme instanceof AbstractColorsScheme ?
((AbstractColorsScheme)myParentScheme).getFallbackAttributes(baseKey) : null;
TextAttributes value = myAttributesMap.get(key);
if (baseKey != null && value.isFallbackEnabled()) {
if (isParentOverwritingInheritance(key)) {
attrElements.addContent(new Element(OPTION_ELEMENT).setAttribute(NAME_ATTR, key.getExternalName()).setAttribute(BASE_ATTRIBUTES_ATTR, baseKey.getExternalName()));
if (attributes == USE_INHERITED_MARKER) {
if (baseKey != null) {
attrElements.addContent(new Element(OPTION_ELEMENT)
.setAttribute(NAME_ATTR, key.getExternalName())
.setAttribute(BASE_ATTRIBUTES_ATTR, baseKey.getExternalName()));
}
continue;
}
if (myParentScheme != null) {
// fallback attributes must be not used, otherwise derived scheme as copy will not have such ke
TextAttributes parentAttributes = myParentScheme instanceof AbstractColorsScheme
? ((AbstractColorsScheme)myParentScheme).getDirectlyDefinedAttributes(key)
: myParentScheme.getAttributes(key);
if (parentAttributes != null && attributes.equals(parentAttributes)) {
continue;
}
}
else {
if (value.containsValue() && !value.equals(defaultAttr) || defaultAttr == defaultFallbackAttr) {
Element valueElement = new Element(VALUE_ELEMENT);
value.writeExternal(valueElement);
attrElements.addContent(new Element(OPTION_ELEMENT).setAttribute(NAME_ATTR, key.getExternalName()).addContent(valueElement));
Element valueElement = new Element(VALUE_ELEMENT);
attributes.writeExternal(valueElement);
attrElements.addContent(new Element(OPTION_ELEMENT).setAttribute(NAME_ATTR, key.getExternalName()).addContent(valueElement));
}
}
public void optimizeAttributeMap() {
EditorColorsScheme parentScheme = myParentScheme;
if (parentScheme == null) {
return;
}
for (TextAttributesKey key : new ArrayList<>(myAttributesMap.keySet())) {
TextAttributes attributes = myAttributesMap.get(key);
if (attributes == USE_INHERITED_MARKER) {
if (key.getFallbackAttributeKey() == null) {
myAttributesMap.remove(key);
}
continue;
}
TextAttributes parentAttributes = parentScheme instanceof DefaultColorsScheme
? ((DefaultColorsScheme)parentScheme).getAttributes(key, false)
: parentScheme.getAttributes(key);
if (Comparing.equal(parentAttributes, attributes)) {
myAttributesMap.remove(key);
}
}
}
@@ -661,15 +694,6 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
return metaInfoElement;
}
private boolean isParentOverwritingInheritance(@NotNull TextAttributesKey key) {
TextAttributes parentAttrs =
myParentScheme instanceof AbstractColorsScheme ? ((AbstractColorsScheme)myParentScheme).getDirectlyDefinedAttributes(key) : null;
if (parentAttrs != null) {
return !parentAttrs.isFallbackEnabled();
}
return false;
}
protected Color getOwnColor(ColorKey key) {
return myColorsMap.get(key);
}
@@ -698,7 +722,6 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
}
}
return true;
}
@NotNull
@@ -756,15 +779,13 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
myConsoleLineSpacing = lineSpacing;
}
protected TextAttributes getFallbackAttributes(TextAttributesKey fallbackKey) {
if (fallbackKey == null) return null;
protected TextAttributes getFallbackAttributes(@NotNull TextAttributesKey fallbackKey) {
TextAttributes fallbackAttributes = getDirectlyDefinedAttributes(fallbackKey);
if (fallbackAttributes != null) {
if (!fallbackAttributes.isFallbackEnabled() || fallbackKey.getFallbackAttributeKey() == null) {
return fallbackAttributes;
}
TextAttributesKey fallbackKeyFallbackKey = fallbackKey.getFallbackAttributeKey();
if (fallbackAttributes != null && (fallbackAttributes != USE_INHERITED_MARKER || fallbackKeyFallbackKey == null)) {
return fallbackAttributes;
}
return getFallbackAttributes(fallbackKey.getFallbackAttributeKey());
return fallbackKeyFallbackKey == null ? null : getFallbackAttributes(fallbackKeyFallbackKey);
}
/**
@@ -782,10 +803,6 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
return myParentScheme instanceof AbstractColorsScheme ? ((AbstractColorsScheme)myParentScheme).getDirectlyDefinedAttributes(key) : null;
}
protected static boolean containsValue(@Nullable TextAttributes attributes) {
return attributes != null && attributes.containsValue();
}
public boolean isSaveNeeded() {
return myIsSaveNeeded;
}
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.editor.colors.impl;
import com.intellij.openapi.editor.colors.ColorKey;
@@ -37,14 +36,23 @@ public class DefaultColorsScheme extends AbstractColorsScheme implements ReadOnl
@Override
@Nullable
public TextAttributes getAttributes(TextAttributesKey key) {
if (key == null) return null;
return key == null ? null : getAttributes(key, true);
}
@Nullable
public TextAttributes getAttributes(@NotNull TextAttributesKey key, boolean isUseDefault) {
TextAttributes attrs = myAttributesMap.get(key);
if (attrs == null) {
if (key.getFallbackAttributeKey() != null) {
attrs = getFallbackAttributes(key.getFallbackAttributeKey());
if (attrs != null && !attrs.isFallbackEnabled()) return attrs;
if (attrs != null && attrs != TextAttributes.USE_INHERITED_MARKER) {
return attrs;
}
}
if (isUseDefault) {
attrs = getKeyDefaults(key);
}
attrs = getKeyDefaults(key);
}
return attrs;
}
@@ -26,6 +26,8 @@ import org.jetbrains.annotations.Nullable;
import java.awt.*;
import static com.intellij.openapi.editor.markup.TextAttributes.USE_INHERITED_MARKER;
public class EditorColorsSchemeImpl extends AbstractColorsScheme implements ExternalizableScheme {
public EditorColorsSchemeImpl(EditorColorsScheme parentScheme) {
super(parentScheme);
@@ -33,7 +35,7 @@ public class EditorColorsSchemeImpl extends AbstractColorsScheme implements Exte
@Override
public void setAttributes(@NotNull TextAttributesKey key, TextAttributes attributes) {
if (!attributes.equals(getAttributes(key))) {
if (attributes == USE_INHERITED_MARKER || !attributes.equals(getAttributes(key))) {
myAttributesMap.put(key, attributes);
}
}
@@ -47,30 +49,24 @@ public class EditorColorsSchemeImpl extends AbstractColorsScheme implements Exte
@Override
public TextAttributes getAttributes(@Nullable TextAttributesKey key) {
TextAttributes attributes = key == null ? null : getOwnAttributes(key);
return attributes == null ? myParentScheme.getAttributes(key) : attributes;
}
@Nullable
private TextAttributes getOwnAttributes(@NotNull TextAttributesKey key) {
TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
TextAttributes attributes = getDirectlyDefinedAttributes(key);
if (fallbackKey == null) {
if (containsValue(attributes)) {
if (key != null) {
TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
TextAttributes attributes = getDirectlyDefinedAttributes(key);
if (fallbackKey == null) {
return attributes;
}
else {
if (attributes != null && attributes != USE_INHERITED_MARKER) {
return attributes;
}
attributes = getFallbackAttributes(fallbackKey);
if (attributes != null) {
return attributes;
}
}
}
else {
if (containsValue(attributes) && !attributes.isFallbackEnabled()) {
return attributes;
}
attributes = getFallbackAttributes(fallbackKey);
if (containsValue(attributes)) {
return attributes;
}
}
return null;
return myParentScheme.getAttributes(key);
}
@Nullable
@@ -53,25 +53,22 @@ class TextAttributesReader extends ValueElementReader {
*/
@Override
public <T> T read(Class<T> type, Element element) {
if (TextAttributes.class.equals(type)) {
TextAttributes attributes = new TextAttributes();
if (element != null) {
attributes.setAttributes(
readChild(Color.class, element, FOREGROUND),
readChild(Color.class, element, BACKGROUND),
readChild(Color.class, element, EFFECT_COLOR),
readChild(Color.class, element, ERROR_STRIPE),
Effect.read(this, element),
FontStyle.read(this, element));
// needed for compatibility with TextAttributes(Element)
if (attributes.isEmpty()) {
attributes.setEnforceEmpty(true);
}
}
//noinspection unchecked
return (T)attributes;
if (!TextAttributes.class.equals(type)) {
return super.read(type, element);
}
return super.read(type, element);
TextAttributes attributes = new TextAttributes();
if (element != null) {
attributes.setAttributes(
readChild(Color.class, element, FOREGROUND),
readChild(Color.class, element, BACKGROUND),
readChild(Color.class, element, EFFECT_COLOR),
readChild(Color.class, element, ERROR_STRIPE),
Effect.read(this, element),
FontStyle.read(this, element));
}
//noinspection unchecked
return (T)attributes;
}
/**
Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 B

After

Width:  |  Height:  |  Size: 181 B

+11
View File
@@ -0,0 +1,11 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<title>threads</title>
<g>
<rect x="3.00107" y="4.8" width="9.99893" height="1.2" rx="0.6" ry="0.6" fill="#9aa7b0" opacity="0.7"/>
<rect x="3.00107" y="8.7998" width="9.99893" height="1.2" rx="0.6" ry="0.6" fill="#9aa7b0" opacity="0.7"/>
<rect x="3.00107" y="10.8" width="9.99893" height="1.2" rx="0.6" ry="0.6" fill="#9aa7b0" opacity="0.7"/>
<path d="M13.991,1.82861a0.32754,0.32754,0,0,0-.2367-0.32129,3.83122,3.83122,0,0,0-.83088-0.207,26.9423,26.9423,0,0,0-3.09559-.26123C9.22708,1.0166,8.62608,1.01953,8.09984,1L8,1.002,7.90016,1c-0.52624.01953-1.12724,0.0166-1.728,0.03906a26.9423,26.9423,0,0,0-3.09559.26123,3.83122,3.83122,0,0,0-.83088.207,0.32754,0.32754,0,0,0-.2367.32129,5.715,5.715,0,0,0,.00438.70166A2.34713,2.34713,0,0,0,3.98172,4C4.64871,3.98535,6.34067,3.97852,8,3.97852S11.35129,3.98535,12.01828,4a2.34713,2.34713,0,0,0,1.96835-1.46973A5.715,5.715,0,0,0,13.991,1.82861ZM8.0151,2.43945L8,2.439l-0.0151.00049c-1.41654,0-2.565-.21826-2.565-0.4873A1.293,1.293,0,0,1,6.45927,1.562l0.02143-.00439,0.0095-.00049a10.23432,10.23432,0,0,1,1.02862-.084c0.142-.00586.28418-0.00781,0.4264-0.0083L7.9849,1.46436,8,1.46484l0.0151-.00049L8.05479,1.46484c0.14221,0.00049.28443,0.00244,0.4264,0.0083a10.23432,10.23432,0,0,1,1.02862.084L9.5193,1.55762,9.54073,1.562a1.293,1.293,0,0,1,1.03933.39014C10.58007,2.22119,9.43164,2.43945,8.0151,2.43945Z" fill="#40b6e0"/>
<path d="M13.98661,14.13333a2.34691,2.34691,0,0,0-1.9835-1.29122c-0.14118,0-3.90391.01887-3.9873,0.0193-0.08364-.00043-3.84636-0.0193-3.98755-0.0193a2.37927,2.37927,0,0,0-1.9995,1.29122,4.4036,4.4036,0,0,0-.00439.61624A0.26614,0.26614,0,0,0,2.2058,15H13.82559a0.25109,0.25109,0,0,0,.16541-0.25044A4.4036,4.4036,0,0,0,13.98661,14.13333Z" fill="#40b6e0"/>
<path d="M14.44657,7.55537A2.71806,2.71806,0,0,0,13.26,6.87178a3.81489,3.81489,0,0,0-.869-0.06885L12.37635,6.8H3.59947a0.6001,0.6001,0,0,0,0,1.2002h8.77688c0.20746,0.00049.423,0,.61264,0a1.17855,1.17855,0,0,1,1.02683,1.08643c0.04042,0.4751-.03.69678,0,1.13721a0.50325,0.50325,0,0,0,.57233.59912c0.37033,0,.39558-0.46832.3985-0.59912C14.98665,10.22383,15.13445,8.27461,14.44657,7.55537Z" fill="#9aa7b0" opacity="0.7"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 295 B

@@ -0,0 +1,11 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<title>threads@2x</title>
<g>
<rect x="6.00214" y="9.6" width="19.99786" height="2.4" rx="0.6" ry="0.6" fill="#9aa7b0" opacity="0.7"/>
<rect x="6.00214" y="17.59961" width="19.99786" height="2.4" rx="0.6" ry="0.6" fill="#9aa7b0" opacity="0.7"/>
<rect x="6.00214" y="21.6" width="19.99786" height="2.4" rx="0.6" ry="0.6" fill="#9aa7b0" opacity="0.7"/>
<path d="M27.982,3.65723a0.65509,0.65509,0,0,0-.4734-0.64258,7.66244,7.66244,0,0,0-1.66176-.41406,53.8846,53.8846,0,0,0-6.19118-.52246C18.45417,2.0332,17.25217,2.03906,16.19968,2,16.1315,2.001,16.06818,2.00293,16,2.00391,15.93181,2.00293,15.8685,2.001,15.80031,2c-1.05248.03906-2.25448,0.0332-3.456,0.07813a53.8846,53.8846,0,0,0-6.19118.52246,7.66244,7.66244,0,0,0-1.66176.41406,0.65509,0.65509,0,0,0-.4734.64258,11.43,11.43,0,0,0,.00877,1.40332C4.08908,5.64941,5.77714,8.04785,7.96344,8,9.29743,7.9707,12.68134,7.957,16,7.957S22.70257,7.9707,24.03656,8c2.1863,0.04785,3.87436-2.35059,3.9367-2.93945A11.43,11.43,0,0,0,27.982,3.65723ZM16.0302,4.87891L16,4.87793l-0.0302.001c-2.83308,0-5.12994-.43652-5.12994-0.97461,0-.32129.82358-0.60254,2.07866-0.78027,0.01461-.00293.02874-0.00684,0.04286-0.00879l0.019-.001a20.46864,20.46864,0,0,1,2.05723-.168c0.28394-.01172.56837-0.01563,0.8528-0.0166,0.02679,0,.05211-0.001.07939-0.001L16,2.92969l0.0302-.001c0.02727,0,.0526.001,0.07939,0.001,0.28443,0.001.56886,0.00488,0.8528,0.0166a20.46864,20.46864,0,0,1,2.05723.168l0.019,0.001c0.01412,0.002.02825,0.00586,0.04286,0.00879,1.25509,0.17773,2.07866.459,2.07866,0.78027C21.16013,4.44238,18.86328,4.87891,16.0302,4.87891Z" fill="#40b6e0"/>
<path d="M27.97323,28.26665a4.69382,4.69382,0,0,0-3.967-2.58244c-0.28237,0-7.80781.03774-7.9746,0.0386-0.16728-.00086-7.69272-0.0386-7.97509-0.0386a4.75855,4.75855,0,0,0-3.999,2.58244,8.8072,8.8072,0,0,0-.00878,1.23247A0.53227,0.53227,0,0,0,4.41159,30H27.65118a0.50218,0.50218,0,0,0,.33082-0.50088A8.8072,8.8072,0,0,0,27.97323,28.26665Z" fill="#40b6e0"/>
<path d="M28.89314,15.11074A5.43613,5.43613,0,0,0,26.52,13.74355a7.62978,7.62978,0,0,0-1.73809-.1377c-0.01023,0-.01851-0.00586-0.02922-0.00586H7.19894a1.2002,1.2002,0,0,0,0,2.40039H24.7527c0.41492,0.001.84591,0,1.22528,0a2.3571,2.3571,0,0,1,2.05365,2.17285c0.08084,0.9502-.0599,1.39355,0,2.27441a1.00651,1.00651,0,0,0,1.14466,1.19824c0.74066,0,.79116-0.93665.797-1.19824C29.97329,20.44766,30.2689,16.54922,28.89314,15.11074Z" fill="#9aa7b0" opacity="0.7"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 113 B

@@ -0,0 +1,7 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<title>any_type</title>
<g>
<polygon points="6 0 2 4 6 4 6 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
<polygon points="7 0 7 4 7 5 6 5 2 5 2 15 13 15 13 0 7 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 153 B

@@ -0,0 +1,7 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<title>any_type@2x</title>
<g>
<polygon points="12 0 4 8 12 8 12 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
<polygon points="14 0 14 8 14 10 12 10 4 10 4 30 26 30 26 0 14 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 B

After

Width:  |  Height:  |  Size: 106 B

+24
View File
@@ -0,0 +1,24 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<title>archive</title>
<g>
<g>
<polygon points="5 0 2 0 2 5 2 15 5 15 5 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
<rect x="10" width="3" height="15" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
</g>
<polygon points="7 2 5 2 6 3 8 3 7 2" fill="#40b6e0"/>
<polygon points="7 0 5 0 6 1 8 1 7 0" fill="#40b6e0"/>
<polygon points="7 8 5 8 6 9 8 9 7 8" fill="#40b6e0"/>
<polygon points="7 10 5 10 6 11 8 11 7 10" fill="#40b6e0"/>
<polygon points="7 12 5 12 6 13 8 13 7 12" fill="#40b6e0"/>
<polygon points="7 14 5 14 6 15 8 15 7 14" fill="#40b6e0"/>
<polygon points="7 4 5 4 6 5 8 5 7 4" fill="#40b6e0"/>
<polygon points="7 6 5 6 6 7 8 7 7 6" fill="#40b6e0"/>
<polygon points="8 3 10 3 9 4 7 4 8 3" fill="#40b6e0"/>
<polygon points="8 1 10 1 9 2 7 2 8 1" fill="#40b6e0"/>
<polygon points="8 9 10 9 9 10 7 10 8 9" fill="#40b6e0"/>
<polygon points="8 11 10 11 9 12 7 12 8 11" fill="#40b6e0"/>
<polygon points="8 13 10 13 9 14 7 14 8 13" fill="#40b6e0"/>
<polygon points="8 5 10 5 9 6 7 6 8 5" fill="#40b6e0"/>
<polygon points="8 7 10 7 9 8 7 8 8 7" fill="#40b6e0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 B

After

Width:  |  Height:  |  Size: 149 B

@@ -0,0 +1,24 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<title>archive@2x</title>
<g>
<g>
<polygon points="10 0 4 0 4 10 4 30 10 30 10 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
<rect x="20" width="6" height="30" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
</g>
<polygon points="14 4 10 4 12 6 16 6 14 4" fill="#40b6e0"/>
<polygon points="14 0 10 0 12 2 16 2 14 0" fill="#40b6e0"/>
<polygon points="14 16 10 16 12 18 16 18 14 16" fill="#40b6e0"/>
<polygon points="14 20 10 20 12 22 16 22 14 20" fill="#40b6e0"/>
<polygon points="14 24 10 24 12 26 16 26 14 24" fill="#40b6e0"/>
<polygon points="14 28 10 28 12 30 16 30 14 28" fill="#40b6e0"/>
<polygon points="14 8 10 8 12 10 16 10 14 8" fill="#40b6e0"/>
<polygon points="14 12 10 12 12 14 16 14 14 12" fill="#40b6e0"/>
<polygon points="16 6 20 6 18 8 14 8 16 6" fill="#40b6e0"/>
<polygon points="16 2 20 2 18 4 14 4 16 2" fill="#40b6e0"/>
<polygon points="16 18 20 18 18 20 14 20 16 18" fill="#40b6e0"/>
<polygon points="16 22 20 22 18 24 14 24 16 22" fill="#40b6e0"/>
<polygon points="16 26 20 26 18 28 14 28 16 26" fill="#40b6e0"/>
<polygon points="16 10 20 10 18 12 14 12 16 10" fill="#40b6e0"/>
<polygon points="16 14 20 14 18 16 14 16 16 14" fill="#40b6e0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 225 B

+12
View File
@@ -0,0 +1,12 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<title>as</title>
<g>
<g>
<polygon points="6 0 2 4 6 4 6 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
<polygon points="7 0 7 4 7 5 6 5 2 5 2 8 13 8 13 0 7 0" fill="#9aa7b0" opacity="0.7" style="isolation: isolate"/>
</g>
<rect x="1" y="9" width="15" height="7" fill="#f26522" opacity="0.6"/>
<path d="M4.10964,10H4.89036L7,15H6.10941L5.62313,13.80111H3.35623L2.86326,15H2ZM5.3153,13.02841l-0.82869-1.986-0.822,1.986H5.3153Z" fill="#231f20" opacity="0.6"/>
<path d="M10.257,12.11133c-1.05054-.22217-1.2995-0.38916-1.2995-0.76416V11.333a0.73775,0.73775,0,0,1,.88694-0.57617c0.00848,0,.012-0.00391.02-0.00439v0.00146h1.48964V10H9.95664l-0.00082.00684C9.923,10.00586,9.89344,10,9.85979,10A1.61237,1.61237,0,0,0,8,11.40967v0.01416c0,0.89551.65413,1.20117,1.81356,1.45117,1.01115,0.208,1.22892.396,1.22892,0.74316v0.01367a0.79588,0.79588,0,0,1-.96464.61084c-0.01614,0-.02982-0.00342-0.04569-0.00391v0.00684h-1.558v0.75391L10.033,14.998,10.05431,15C11.19841,15,12,14.4585,12,13.54883V13.53418C12,12.72949,11.40825,12.36133,10.257,12.11133Z" fill="#231f20" opacity="0.6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 376 B

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