mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+43
-3
@@ -69,10 +69,13 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
if (candidates.isEmpty()) return;
|
||||
final List<ImplicitUsageProvider> implicitUsageProviders = ImplicitUsageProvider.EP_NAME.getExtensionList();
|
||||
|
||||
PsiClass scope = PsiTreeUtil.getTopmostParentOfType(aClass, PsiClass.class);
|
||||
if (scope == null) scope = aClass;
|
||||
|
||||
FieldLoop:
|
||||
for (final PsiField field : candidates) {
|
||||
if (usedFields.contains(field) && !hasImplicitReadOrWriteUsage(field, implicitUsageProviders)) {
|
||||
final Query<PsiReference> references = ReferencesSearch.search(field, new LocalSearchScope(aClass));
|
||||
final Query<PsiReference> references = ReferencesSearch.search(field, new LocalSearchScope(scope));
|
||||
final Map<PsiCodeBlock, Collection<PsiReference>> refs = new HashMap<>();
|
||||
for (PsiReference reference : references.findAll()) {
|
||||
final PsiElement element = reference.getElement();
|
||||
@@ -151,6 +154,11 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
//do not go inside class initializer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {
|
||||
// do not go inside lambda
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
excludeFieldCandidate(expression);
|
||||
@@ -295,7 +303,7 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
|
||||
private static boolean groupReferenceByCodeBlocks(Map<PsiCodeBlock, Collection<PsiReference>> refs, PsiReference psiReference) {
|
||||
final PsiElement element = psiReference.getElement();
|
||||
final PsiCodeBlock block = PsiTreeUtil.getTopmostParentOfType(element, PsiCodeBlock.class);
|
||||
final PsiCodeBlock block = getTopmostBlock(element);
|
||||
if (block == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -310,6 +318,17 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiCodeBlock getTopmostBlock(@NotNull PsiElement element) {
|
||||
PsiElement parent = element.getParent();
|
||||
PsiCodeBlock block = null;
|
||||
while (parent != null && !(parent instanceof PsiClass)) {
|
||||
if (parent instanceof PsiCodeBlock) block = (PsiCodeBlock)parent;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
private static boolean findExistentBlock(Map<PsiCodeBlock, Collection<PsiReference>> refs,
|
||||
PsiReference psiReference,
|
||||
PsiCodeBlock block,
|
||||
@@ -365,8 +384,29 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitJavaFile(PsiJavaFile file) {
|
||||
final JavaElementVisitor visitor = new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
super.visitClass(aClass);
|
||||
Arrays.stream(aClass.getChildren()).forEach(c -> c.accept(this));
|
||||
doCheckClass(aClass, holder, EXCLUDE_ANNOS, IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDeclarationStatement(PsiDeclarationStatement statement) {
|
||||
super.visitDeclarationStatement(statement);
|
||||
Arrays.stream(statement.getDeclaredElements()).forEach(d -> d.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
super.visitMethod(method);
|
||||
final PsiCodeBlock body = method.getBody();
|
||||
if (body != null) Arrays.stream(body.getChildren()).forEach(c -> c.accept(this));
|
||||
}
|
||||
};
|
||||
for (PsiClass aClass : file.getClasses()) {
|
||||
doCheckClass(aClass, holder, EXCLUDE_ANNOS, IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS);
|
||||
aClass.accept(visitor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Convert field to local variable in method 'test'" "true"
|
||||
class Foo {
|
||||
void test() {
|
||||
class Bar {
|
||||
|
||||
void test() {
|
||||
int x = 2; // could be local
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Convert to local" "true"
|
||||
class Outer {
|
||||
|
||||
void test() {
|
||||
class Local {
|
||||
|
||||
void foo() {
|
||||
String s = "1";
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
void bar() {
|
||||
String s = "2";
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Convert field to local variable in method 'test'" "true"
|
||||
class Foo {
|
||||
static class Bar {
|
||||
|
||||
void test() {
|
||||
int x = 2; // could be local
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Convert to local" "true"
|
||||
class Test {
|
||||
|
||||
private Runnable r = () -> {
|
||||
String field = "foo";
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// "Fix all 'Field can be local' problems in file" "false"
|
||||
class Outer {
|
||||
|
||||
void test(Inner inner) {
|
||||
System.out.println(inner.field);
|
||||
}
|
||||
|
||||
class Inner {
|
||||
private final String f<caret>ield;
|
||||
|
||||
Inner(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Convert field to local variable in method 'test'" "true"
|
||||
class Foo {
|
||||
void test() {
|
||||
class Bar {
|
||||
private int <caret>x;
|
||||
|
||||
void test() {
|
||||
x = 2; // could be local
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// "Convert to local" "true"
|
||||
class Outer {
|
||||
|
||||
void test() {
|
||||
class Local {
|
||||
private String <caret>s;
|
||||
|
||||
void foo() {
|
||||
s = "1";
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
void bar() {
|
||||
s = "2";
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Convert field to local variable in method 'test'" "true"
|
||||
class Foo {
|
||||
static class Bar {
|
||||
private int <caret>x;
|
||||
|
||||
void test() {
|
||||
x = 2; // could be local
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Convert to local" "true"
|
||||
class Test {
|
||||
|
||||
private String <caret>field;
|
||||
|
||||
private Runnable r = () -> {
|
||||
field = "foo";
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
private int value = 0;
|
||||
|
||||
public class Inner {
|
||||
private final int myValue;
|
||||
private final int <warning descr="Field can be converted to a local variable">myValue</warning>;
|
||||
|
||||
public Inner() {
|
||||
myValue = value++;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
private int <warning descr="Field can be converted to a local variable">value</warning> = 0;
|
||||
|
||||
public class Inner {
|
||||
private final int myValue;
|
||||
private final int <warning descr="Field can be converted to a local variable">myValue</warning>;
|
||||
|
||||
public Inner() {
|
||||
myValue = value;
|
||||
|
||||
+9
-3
@@ -438,7 +438,7 @@
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="7bb4" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="true" hgap="-1" vgap="0">
|
||||
<grid id="7bb4" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="0">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="2" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
@@ -486,7 +486,7 @@
|
||||
<text resource-bundle="messages/ApplicationBundle" key="label.use.custom.soft.wraps.indent"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="8800e" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="8800e" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
@@ -503,12 +503,18 @@
|
||||
<text resource-bundle="messages/ApplicationBundle" key="checkbox.use.soft.wraps.at.editor"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="2a016" class="com.intellij.ui.components.JBTextField" binding="mySoftWrapFileMasks">
|
||||
<component id="2a016" class="com.intellij.ui.components.JBTextField" binding="mySoftWrapFileMasks" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="ed230" class="javax.swing.JLabel" binding="mySoftWrapFileMasksHint" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.options.ex.ConfigurableWrapper;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.ui.panel.ComponentPanelBuilder;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -39,6 +40,7 @@ import com.intellij.ui.ListCellRendererWrapper;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBTextField;
|
||||
import com.intellij.util.ui.JBEmptyBorder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -99,6 +101,7 @@ public class EditorOptionsPanel extends CompositeConfigurable<ErrorOptionsProvid
|
||||
private JCheckBox myCbKeepTrailingSpacesOnCaretLine;
|
||||
private JTextField myRecentLocationsLimitField;
|
||||
private JBTextField mySoftWrapFileMasks;
|
||||
private JLabel mySoftWrapFileMasksHint;
|
||||
|
||||
private static final String ACTIVE_COLOR_SCHEME = ApplicationBundle.message("combobox.richcopy.color.scheme.active");
|
||||
private static final UINumericRange RECENT_FILES_RANGE = new UINumericRange(50, 1, 500);
|
||||
@@ -377,6 +380,12 @@ public class EditorOptionsPanel extends CompositeConfigurable<ErrorOptionsProvid
|
||||
ApplicationManager.getApplication().getMessageBus().syncPublisher(EditorOptionsListener.OPTIONS_PANEL_TOPIC).changesApplied();
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
mySoftWrapFileMasks = new JBTextField();
|
||||
mySoftWrapFileMasksHint = ComponentPanelBuilder.createCommentComponent(ApplicationBundle.message("soft.wraps.file.masks.hint"), true);
|
||||
mySoftWrapFileMasksHint.setBorder(new JBEmptyBorder(ComponentPanelBuilder.computeCommentInsets(mySoftWrapFileMasks, true)));
|
||||
}
|
||||
|
||||
private static boolean setRecentLocationLimit(@NotNull UISettings uiSettings, @NotNull String recentLocationsLimit) {
|
||||
try {
|
||||
int newRecentLocationsLimit = Integer.parseInt(recentLocationsLimit.trim());
|
||||
|
||||
@@ -175,9 +175,6 @@ class ITNProxy {
|
||||
|
||||
HttpURLConnection connection = post(new URL(NEW_THREAD_POST_URL), createRequest(login, password, error));
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_BAD_REQUEST && StringUtil.isEmpty(password)) {
|
||||
throw new NoSuchEAPUserException(login);
|
||||
}
|
||||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
throw new InternalEAPException(DiagnosticBundle.message("error.http.result.code", responseCode));
|
||||
}
|
||||
|
||||
@@ -432,8 +432,9 @@ radio.close.less.frequently.used.files=Close unused
|
||||
radio.close.non.modified.files.first=Close unchanged
|
||||
label.when.number.of.opened.editors.exceeds.tab.limit=<html>When tabs exceed the limit:</html>
|
||||
group.soft.wraps=Soft Wraps
|
||||
checkbox.use.soft.wraps.at.editor=Soft-wrap file types:
|
||||
soft.wraps.file.masks.empty.text=No file types
|
||||
checkbox.use.soft.wraps.at.editor=Soft-wrap files:
|
||||
soft.wraps.file.masks.empty.text=No files
|
||||
soft.wraps.file.masks.hint=Use ; to separate patterns, * and ? as wildcards
|
||||
checkbox.use.soft.wraps.at.console=Use soft wraps in console
|
||||
checkbox.use.custom.soft.wraps.indent=Use original line's indent for wrapped parts
|
||||
label.use.custom.soft.wraps.indent=Additional shift:
|
||||
|
||||
@@ -1579,10 +1579,6 @@ typescript.service.node.arguments=
|
||||
typescript.service.node.arguments.description=Node options to use when starting TypeScript service process
|
||||
javascript.exclude.source.if.package.has.typings=true
|
||||
javascript.exclude.source.if.package.has.typings.description=Don't index JavaScript files in a node module if it has type declaration files
|
||||
javascript.flow.lazy.mode=false
|
||||
javascript.flow.lazy.mode.description=Passes '--lazy-mode fs' to flow server command
|
||||
javascript.flow.use.lsp=false
|
||||
javascript.flow.use.lsp.description=Enables using Language Server Protocol for communication with Flow
|
||||
|
||||
javascript.linters.prevent.detection=false
|
||||
javascript.linters.prevent.enable.on.project.opening.description=Disables JS linter detection on project opening
|
||||
|
||||
+8
@@ -1,10 +1,12 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParameterListOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
|
||||
|
||||
@@ -17,4 +19,10 @@ public interface GrFunctionalExpression extends GrExpression, GrParameterListOwn
|
||||
|
||||
@Nullable
|
||||
PsiType getReturnType();
|
||||
|
||||
@NotNull
|
||||
GrStatement[] getStatements();
|
||||
|
||||
@Nullable
|
||||
PsiElement getArrow();
|
||||
}
|
||||
|
||||
+9
@@ -1,10 +1,19 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api;
|
||||
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
|
||||
/**
|
||||
* Represents a Groovy lambda expression body.
|
||||
*/
|
||||
public interface GrLambdaBody extends GrControlFlowOwner {
|
||||
|
||||
@NotNull
|
||||
GrLambdaExpression getLambdaExpression();
|
||||
|
||||
@Nullable
|
||||
PsiType getReturnType();
|
||||
}
|
||||
|
||||
+6
@@ -1,6 +1,8 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -14,4 +16,8 @@ public interface GrLambdaExpression extends GrFunctionalExpression {
|
||||
*/
|
||||
@Nullable
|
||||
GrLambdaBody getBody();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
PsiElement getArrow();
|
||||
}
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ public interface GrClosableBlock extends GrFunctionalExpression, GrCodeBlock {
|
||||
@Override
|
||||
GrParameter[] getAllParameters();
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
PsiElement getArrow();
|
||||
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @author ven
|
||||
*/
|
||||
public interface Instruction {
|
||||
Instruction[] EMPTY_ARRAY = new Instruction[0];
|
||||
|
||||
@NotNull
|
||||
Iterable<Instruction> successors(@NotNull CallEnvironment environment);
|
||||
|
||||
+51
-31
@@ -17,11 +17,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrInExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrTryResourceList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrCondition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
@@ -99,8 +99,9 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
final PsiElement lbrace = block.getLBrace();
|
||||
if (lbrace != null && parent instanceof GrMethod) {
|
||||
for (GrParameter parameter : ((GrMethod)parent).getParameters()) {
|
||||
if (myPolicy.isVariableInitialized(parameter)) {
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, ReadWriteVariableInstruction.WRITE));
|
||||
String parameterName = parameter.getName();
|
||||
if (myPolicy.isVariableInitialized(parameter) && parameterName != null) {
|
||||
addNode(new ReadWriteVariableInstruction(parameterName, parameter, ReadWriteVariableInstruction.WRITE));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,6 +115,12 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambdaBody(@NotNull GrLambdaBody body) {
|
||||
addFunctionalExpressionParameters(body.getLambdaExpression());
|
||||
addControlFlowInstructions(body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFile(@NotNull GroovyFileBase file) {
|
||||
super.visitFile(file);
|
||||
@@ -133,14 +140,20 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
}
|
||||
|
||||
public Instruction[] buildControlFlow(GroovyPsiElement scope) {
|
||||
if (scope instanceof GrLambdaExpression) {
|
||||
GrLambdaBody body = ((GrLambdaExpression)scope).getBody();
|
||||
return body != null ? body.getControlFlow() : Instruction.EMPTY_ARRAY;
|
||||
}
|
||||
myFinallyCount = 0;
|
||||
myInstructionNumber = 0;
|
||||
|
||||
myScope = scope;
|
||||
|
||||
startNode(null);
|
||||
|
||||
if (scope instanceof GrClosableBlock) {
|
||||
buildFlowForClosure((GrClosableBlock)scope);
|
||||
addFunctionalExpressionParameters((GrFunctionalExpression)scope);
|
||||
addControlFlowInstructions((GrControlFlowOwner)scope);
|
||||
}
|
||||
else {
|
||||
scope.accept(this);
|
||||
@@ -150,7 +163,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
checkPending(end); //collect return edges
|
||||
|
||||
|
||||
return assertValidPsi(myInstructions.toArray(new Instruction[0]));
|
||||
return assertValidPsi(myInstructions.toArray(Instruction.EMPTY_ARRAY));
|
||||
}
|
||||
|
||||
public static Instruction[] assertValidPsi(Instruction[] instructions) {
|
||||
@@ -163,16 +176,9 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
return instructions;
|
||||
}
|
||||
|
||||
private void buildFlowForClosure(final GrClosableBlock closure) {
|
||||
for (GrParameter parameter : closure.getAllParameters()) {
|
||||
if (myPolicy.isVariableInitialized(parameter)) {
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, ReadWriteVariableInstruction.WRITE));
|
||||
}
|
||||
}
|
||||
|
||||
addNode(new ReadWriteVariableInstruction("owner", closure.getLBrace(), ReadWriteVariableInstruction.WRITE));
|
||||
|
||||
PsiElement child = closure.getFirstChild();
|
||||
private void addControlFlowInstructions(final GrControlFlowOwner owner) {
|
||||
PsiElement child = owner.getFirstChild();
|
||||
while (child != null) {
|
||||
if (child instanceof GroovyPsiElement) {
|
||||
((GroovyPsiElement)child).accept(this);
|
||||
@@ -180,12 +186,25 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
|
||||
final GrStatement[] statements = closure.getStatements();
|
||||
final GrStatement[] statements = owner.getStatements();
|
||||
if (statements.length > 0) {
|
||||
handlePossibleReturn(statements[statements.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFunctionalExpressionParameters(GrFunctionalExpression expression) {
|
||||
for (GrParameter parameter : expression.getAllParameters()) {
|
||||
String parameterName = parameter.getName();
|
||||
if (myPolicy.isVariableInitialized(parameter) && parameterName != null) {
|
||||
addNode(new ReadWriteVariableInstruction(parameterName, parameter, ReadWriteVariableInstruction.WRITE));
|
||||
}
|
||||
}
|
||||
|
||||
PsiElement anchor = expression.getArrow();
|
||||
if (expression instanceof GrClosableBlock) anchor = ((GrClosableBlock)expression).getLBrace();
|
||||
addNode(new ReadWriteVariableInstruction("owner", anchor, ReadWriteVariableInstruction.WRITE));
|
||||
}
|
||||
|
||||
private <T extends InstructionImpl> T addNode(T instruction) {
|
||||
instruction.setNumber(myInstructionNumber++);
|
||||
myInstructions.add(instruction);
|
||||
@@ -211,30 +230,37 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambdaExpression(@NotNull GrLambdaExpression expression) {
|
||||
GrLambdaBody body = expression.getBody();
|
||||
if (body == null) return;
|
||||
ReadWriteVariableInstruction[] reads = ControlFlowBuilderUtil.getReadsWithoutPriorWrites(body.getControlFlow(), false);
|
||||
addReadFromNestedControlFlow(expression, reads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClosure(@NotNull GrClosableBlock closure) {
|
||||
//do not go inside closures except gstring injections
|
||||
if (closure.getParent() instanceof GrStringInjection) {
|
||||
for (GrParameter parameter : closure.getAllParameters()) {
|
||||
if (myPolicy.isVariableInitialized(parameter)) {
|
||||
addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, ReadWriteVariableInstruction.WRITE));
|
||||
}
|
||||
}
|
||||
addNode(new ReadWriteVariableInstruction("owner", closure.getLBrace(), ReadWriteVariableInstruction.WRITE));
|
||||
addFunctionalExpressionParameters(closure);
|
||||
|
||||
super.visitClosure(closure);
|
||||
return;
|
||||
}
|
||||
|
||||
ReadWriteVariableInstruction[] reads = ControlFlowBuilderUtil.getReadsWithoutPriorWrites(closure.getControlFlow(), false);
|
||||
addReadFromNestedControlFlow(closure, reads);
|
||||
}
|
||||
|
||||
private void addReadFromNestedControlFlow(@NotNull PsiElement anchor, @NotNull ReadWriteVariableInstruction[] reads) {
|
||||
for (ReadWriteVariableInstruction read : reads) {
|
||||
PsiElement element = read.getElement();
|
||||
if (!(element instanceof GrReferenceExpression) || myPolicy.isReferenceAccepted((GrReferenceExpression)element)) {
|
||||
addNodeAndCheckPending(new ReadWriteVariableInstruction(read.getVariableName(), closure, ReadWriteVariableInstruction.READ));
|
||||
addNodeAndCheckPending(new ReadWriteVariableInstruction(read.getVariableName(), anchor, ReadWriteVariableInstruction.READ));
|
||||
}
|
||||
}
|
||||
|
||||
addNodeAndCheckPending(new InstructionImpl(closure));
|
||||
addNodeAndCheckPending(new InstructionImpl(anchor));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1186,13 +1212,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
|
||||
final Set<ReadWriteVariableInstruction> vars = collectUsedVariableWithoutInitialization(typeDefinition);
|
||||
|
||||
for (ReadWriteVariableInstruction var : vars) {
|
||||
PsiElement element = var.getElement();
|
||||
if (!(element instanceof GrReferenceExpression) || myPolicy.isReferenceAccepted((GrReferenceExpression)element)) {
|
||||
addNodeAndCheckPending(new ReadWriteVariableInstruction(var.getVariableName(), typeDefinition, ReadWriteVariableInstruction.READ));
|
||||
}
|
||||
}
|
||||
addNodeAndCheckPending(new InstructionImpl(typeDefinition));
|
||||
addReadFromNestedControlFlow(typeDefinition, vars.toArray(ReadWriteVariableInstruction.EMPTY_ARRAY));
|
||||
}
|
||||
|
||||
private static Set<ReadWriteVariableInstruction> collectUsedVariableWithoutInitialization(GrTypeDefinition typeDefinition) {
|
||||
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaBody;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrBlockImpl;
|
||||
|
||||
public class GrLambdaBodyBlockImpl extends GrBlockImpl implements GrLambdaBody {
|
||||
|
||||
public GrLambdaBodyBlockImpl(@NotNull IElementType type, CharSequence buffer) {
|
||||
super(type, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull GroovyElementVisitor visitor) {
|
||||
visitor.visitLambdaBody(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Lambda body block";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTopControlFlowOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl
|
||||
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaBody
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrBlockImpl
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.MethodTypeInferencer
|
||||
|
||||
class GrLambdaBodyBlockImpl(type: IElementType, buffer: CharSequence?) : GrBlockImpl(type, buffer), GrLambdaBody {
|
||||
|
||||
override fun getReturnType(): PsiType? = GroovyPsiManager.inferType(this, MethodTypeInferencer(this))
|
||||
|
||||
override fun isTopControlFlowOwner(): Boolean = true
|
||||
|
||||
override fun getLambdaExpression(): GrLambdaExpression = requireNotNull(parentOfType())
|
||||
|
||||
override fun accept(visitor: GroovyElementVisitor) = visitor.visitLambdaBody(this)
|
||||
|
||||
override fun toString(): String = "Lambda body block"
|
||||
}
|
||||
+6
@@ -2,15 +2,21 @@
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl
|
||||
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaBody
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ControlFlowBuilder
|
||||
|
||||
class GrLambdaBodyExpressionImpl(node: ASTNode) : GroovyPsiElementImpl(node), GrLambdaBody {
|
||||
override fun getReturnType(): PsiType? = getExpression().type
|
||||
|
||||
override fun getLambdaExpression(): GrLambdaExpression = requireNotNull(parentOfType())
|
||||
|
||||
fun getExpression() : GrExpression = findNotNullChildByClass(GrExpression::class.java)
|
||||
|
||||
|
||||
+9
-8
@@ -9,20 +9,19 @@ import com.intellij.psi.scope.PsiScopeProcessor
|
||||
import com.intellij.psi.util.CachedValueProvider.Result.create
|
||||
import com.intellij.psi.util.CachedValuesManager.getCachedValue
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaBody
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.params.GrParameterListImpl
|
||||
|
||||
class GrLambdaExpressionImpl(node: ASTNode) : GrExpressionImpl(node), GrLambdaExpression {
|
||||
|
||||
override fun getParameters(): Array<GrParameter> {
|
||||
return parameterList.parameters
|
||||
}
|
||||
override fun getParameters(): Array<GrParameter> = parameterList.parameters
|
||||
|
||||
override fun getParameterList(): GrParameterList = findNotNullChildByClass(GrParameterListImpl::class.java)
|
||||
|
||||
@@ -47,11 +46,13 @@ class GrLambdaExpressionImpl(node: ASTNode) : GrExpressionImpl(node), GrLambdaEx
|
||||
}
|
||||
}
|
||||
|
||||
override fun getReturnType(): PsiType? = TypeInferenceHelper.getCurrentContext().getExpressionType(this, ::calculateReturnType)
|
||||
override fun getArrow(): PsiElement = findNotNullChildByType(GroovyElementTypes.T_ARROW)
|
||||
|
||||
override fun getType(): PsiType? {
|
||||
return GrClosureType.create(this, true)
|
||||
}
|
||||
override fun getStatements(): Array<GrStatement> = body?.statements ?: emptyArray()
|
||||
|
||||
override fun getReturnType(): PsiType? = body?.returnType
|
||||
|
||||
override fun getType(): PsiType? = GrClosureType.create(this, true)
|
||||
|
||||
override fun toString(): String = "Lambda expression"
|
||||
}
|
||||
|
||||
+17
-4
@@ -34,6 +34,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaBody;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
|
||||
@@ -88,6 +89,13 @@ public class GrReassignedLocalVarsChecker {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambdaBody(@NotNull GrLambdaBody body) {
|
||||
if (getUsedVarsInsideBlock(body).contains(name)) {
|
||||
isReassigned.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(@NotNull GroovyPsiElement element) {
|
||||
if (isReassigned.get()) return;
|
||||
@@ -144,11 +152,11 @@ public class GrReassignedLocalVarsChecker {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<String> getUsedVarsInsideBlock(@NotNull final GrCodeBlock block) {
|
||||
return CachedValuesManager.getCachedValue(block, () -> {
|
||||
private static Set<String> getUsedVarsInsideBlock(@NotNull final GroovyPsiElement element) {
|
||||
return CachedValuesManager.getCachedValue(element, () -> {
|
||||
final Set<String> result = ContainerUtil.newHashSet();
|
||||
|
||||
block.acceptChildren(new GroovyRecursiveElementVisitor() {
|
||||
element.acceptChildren(new GroovyRecursiveElementVisitor() {
|
||||
|
||||
@Override
|
||||
public void visitOpenBlock(@NotNull GrOpenBlock openBlock) {
|
||||
@@ -160,6 +168,11 @@ public class GrReassignedLocalVarsChecker {
|
||||
result.addAll(getUsedVarsInsideBlock(closure));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambdaBody(@NotNull GrLambdaBody body) {
|
||||
result.addAll(getUsedVarsInsideBlock(body));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(@NotNull GrReferenceExpression referenceExpression) {
|
||||
if (referenceExpression.getQualifier() == null && referenceExpression.getReferenceName() != null) {
|
||||
@@ -167,7 +180,7 @@ public class GrReassignedLocalVarsChecker {
|
||||
}
|
||||
}
|
||||
});
|
||||
return CachedValueProvider.Result.create(result, block);
|
||||
return CachedValueProvider.Result.create(result, element);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user