Skip to content

Commit

Permalink
removing all state from Intent implementations in an attempt to solve…
Browse files Browse the repository at this point in the history
… unexpected nullPointerExceptions (#1156)
  • Loading branch information
m0rkeulv committed Mar 19, 2024
1 parent 9fb3721 commit 3ed7971
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static com.intellij.plugins.haxe.util.HaxeElementGenerator.createTypeTag;
import static com.intellij.plugins.haxe.util.UsefulPsiTreeUtil.findParentOfTypeButStopIfTypeIs;

public class AddReturnTypeTagIntention extends BaseIntentionAction {

private HaxeMethod myMethod;
private ResultHolder returnType;

public AddReturnTypeTagIntention() {
}
Expand All @@ -46,43 +45,50 @@ public String getText() {
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (file.getLanguage() != HaxeLanguage.INSTANCE) return false;

attemptToFindMethod(editor, file);
HaxeMethod method = attemptToFindMethod(editor, file);

boolean isMissingTypeTag = myMethod != null
&& myMethod.getModel() != null
&& !myMethod.isConstructor()
&& myMethod instanceof HaxeMethodDeclaration declaration
boolean isMissingTypeTag = method != null
&& method.getModel() != null
&& !method.isConstructor()
&& method instanceof HaxeMethodDeclaration declaration
&& declaration.getTypeTag() == null;
if (isMissingTypeTag) {
HaxeMethodModel model = myMethod.getModel();
HaxeGenericResolver resolver = model.getGenericResolver(null);
resolver = resolver.withTypeParametersAsType(model.getGenericParams());
returnType = model.getReturnType(resolver);
return !(returnType == null);
return !( getReturnType(method) == null);
}
return false;
}


@Override
public void invoke(@NotNull final Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
HaxeMethod method = attemptToFindMethod(editor, file);
if (method != null) {
ResultHolder returnType = getReturnType(method);

String typeText = returnType.isUnknown() ? SpecificTypeReference.VOID : returnType.getType().toPresentationString();
HaxeTypeTag tag = createTypeTag(project, typeText);
PsiParameterList list = method.getParameterList();
PsiElement element = PsiTreeUtil.nextVisibleLeaf(list);
method.addAfter(tag, element);
}
}

String typeText = returnType.isUnknown() ? SpecificTypeReference.VOID : returnType.getType().toPresentationString();
HaxeTypeTag tag = createTypeTag(project, typeText);
PsiParameterList list = myMethod.getParameterList();
PsiElement element = PsiTreeUtil.nextVisibleLeaf(list);
myMethod.addAfter(tag, element);

private static ResultHolder getReturnType(HaxeMethod method) {
HaxeMethodModel model = method.getModel();
HaxeGenericResolver resolver = model.getGenericResolver(null);
resolver = resolver.withTypeParametersAsType(model.getGenericParams());
return model.getReturnType(resolver);
}


private void attemptToFindMethod(Editor editor, PsiFile file) {
private @Nullable HaxeMethod attemptToFindMethod(Editor editor, PsiFile file) {
PsiElement place = file.findElementAt(editor.getCaretModel().getOffset());
if (place instanceof HaxeMethod method) {
myMethod = method;
return method;
}else if (place != null){
myMethod = findParentOfTypeButStopIfTypeIs(place, HaxeMethod.class, HaxeBlockStatement.class);
return findParentOfTypeButStopIfTypeIs(place, HaxeMethod.class, HaxeBlockStatement.class);
}
return null;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@

public class AddTypeTagToFieldIntention extends BaseIntentionAction {

private HaxePsiField myField;
private ResultHolder type;

public AddTypeTagToFieldIntention() {
}

Expand All @@ -48,12 +45,12 @@ public String getText() {
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (file.getLanguage() != HaxeLanguage.INSTANCE) return false;

attemptToFindField(editor, file);

HaxePsiField field = myField;

HaxePsiField field = attemptToFindField(editor, file);;
boolean isMissingTypeTag = field != null && field.getTypeTag() == null;
if (isMissingTypeTag) {
type = HaxeExpressionEvaluator.evaluate(field, new HaxeExpressionEvaluatorContext(field), null).result;
ResultHolder type = HaxeExpressionEvaluator.evaluate(field, new HaxeExpressionEvaluatorContext(field), null).result;
return !(type == null || type.isUnknown());
}
return false;
Expand All @@ -63,23 +60,33 @@ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file
@Override
public void invoke(@NotNull final Project project, Editor editor, PsiFile file) throws IncorrectOperationException {

HaxeTypeTag tag = createTypeTag(project, type.getType().toString());
myField.addAfter(tag, myField.getComponentName());
HaxePsiField field = attemptToFindField(editor, file);;
boolean isMissingTypeTag = field != null && field.getTypeTag() == null;
if (isMissingTypeTag) {
ResultHolder type = HaxeExpressionEvaluator.evaluate(field, new HaxeExpressionEvaluatorContext(field), null).result;
if (!(type == null || type.isUnknown())) {
HaxeTypeTag tag = createTypeTag(project, type.getType().toString());
field.addAfter(tag, field.getComponentName());
}
}

}


private void attemptToFindField(Editor editor, PsiFile file) {
private HaxePsiField attemptToFindField(Editor editor, PsiFile file) {
PsiElement place = file.findElementAt(editor.getCaretModel().getOffset());
HaxeLocalVarDeclarationList varDeclarationList = PsiTreeUtil.getParentOfType(place, HaxeLocalVarDeclarationList.class);

HaxePsiField field = null;
if (varDeclarationList != null) {
List<HaxeLocalVarDeclaration> list = varDeclarationList.getLocalVarDeclarationList();
if (!list.isEmpty())myField = list.get(list.size() - 1);
if (!list.isEmpty())field = list.get(list.size() - 1);
} else if (place instanceof HaxePsiField psiField) {
myField = psiField;
field = psiField;
}else {
myField = PsiTreeUtil.getParentOfType(place, HaxePsiField.class);
field = PsiTreeUtil.getParentOfType(place, HaxePsiField.class);
}
return field;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

public class ConvertPropertyToVariableIntention extends BaseIntentionAction {

private HaxeFieldDeclaration myField;

@Nls
@NotNull
Expand All @@ -35,31 +34,34 @@ public String getText() {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (file.getLanguage() != HaxeLanguage.INSTANCE) return false;
attemptToFindField(editor, file);
HaxeFieldDeclaration field = attemptToFindField(editor, file);

if (myField == null) return false;
if (myField.getTypeTag() == null) return false;
if (myField.getPropertyDeclaration() == null) return false;
if (field == null) return false;
if (field.getTypeTag() == null) return false;
if (field.getPropertyDeclaration() == null) return false;

return true;
}


@Override
public void invoke(@NotNull final Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
myField.getPropertyDeclaration().delete();
HaxeFieldDeclaration field = attemptToFindField(editor, file);
if (field != null && field.getPropertyDeclaration() != null) {
field.getPropertyDeclaration().delete();
}
}





private void attemptToFindField(Editor editor, PsiFile file) {
private HaxeFieldDeclaration attemptToFindField(Editor editor, PsiFile file) {
PsiElement place = file.findElementAt(editor.getCaretModel().getOffset());
if (place instanceof HaxeFieldDeclaration psiField) {
myField = psiField;
return psiField;
} else {
myField = PsiTreeUtil.getParentOfType(place, HaxeFieldDeclaration.class);
return PsiTreeUtil.getParentOfType(place, HaxeFieldDeclaration.class);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,16 @@

public abstract class ConvertVariableToPropertyIntentionBase extends BaseIntentionAction {

private HaxePsiField myField;


@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (file.getLanguage() != HaxeLanguage.INSTANCE) return false;
attemptToFindField(editor, file);
HaxePsiField field = attemptToFindFieldDeclaration(editor, file);

if (myField == null) return false;
if (field == null) return false;

if (myField.getTypeTag() == null) return false;
if (myField.getVarInit() != null) return false;
if (myField.getModel() instanceof HaxeFieldModel model) {
if (field.getTypeTag() == null) return false;
if (field.getVarInit() != null) return false;
if (field.getModel() instanceof HaxeFieldModel model) {
if (model.hasModifier(HaxePsiModifier.INLINE)) return false;
if (model.isProperty()) return false;
}else {
Expand All @@ -42,15 +39,18 @@ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file

@Override
public void invoke(@NotNull final Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
HaxePsiField element = getTempProperty(project);
PsiElement copy = HaxeElementGenerator.createVarDeclaration(project, element.getText()).copy();
myField.replace(copy);
HaxePsiField field = attemptToFindFieldDeclaration(editor, file);
if (field!= null) {
HaxePsiField element = getTempProperty(project, field);
PsiElement copy = HaxeElementGenerator.createVarDeclaration(project, element.getText()).copy();
field.replace(copy);
}

}

@NotNull
private HaxePsiField getTempProperty(@NotNull Project project) {
HaxePsiField element = (HaxePsiField)myField.copy();
private HaxePsiField getTempProperty(@NotNull Project project, HaxePsiField field) {
HaxePsiField element = (HaxePsiField)field.copy();
HaxePropertyDeclaration declaration = generateTmpDeclaration(project);
HaxeComponentName name = element.getComponentName();
HaxeIdentifier identifier = name.getIdentifier();
Expand All @@ -68,18 +68,25 @@ private HaxePropertyDeclaration generateTmpDeclaration(@NotNull Project project)
protected abstract String getPropertyElementString();


private void attemptToFindField(Editor editor, PsiFile file) {
private HaxeFieldDeclaration attemptToFindFieldDeclaration(Editor editor, PsiFile file) {
PsiElement place = file.findElementAt(editor.getCaretModel().getOffset());
HaxeLocalVarDeclarationList varDeclarationList = PsiTreeUtil.getParentOfType(place, HaxeLocalVarDeclarationList.class);

HaxeFieldDeclaration declaration = null;
if (varDeclarationList != null) {
List<HaxeLocalVarDeclaration> list = varDeclarationList.getLocalVarDeclarationList();
if (!list.isEmpty()) myField = list.get(list.size() - 1);
if (!list.isEmpty()){
if(list.get(list.size() - 1) instanceof HaxeFieldDeclaration fieldDeclaration){
declaration = fieldDeclaration;
}
}
}
else if (place instanceof HaxePsiField psiField) {
myField = psiField;
else if (place instanceof HaxeFieldDeclaration fieldDeclaration) {
declaration = fieldDeclaration;
}
else {
myField = PsiTreeUtil.getParentOfType(place, HaxePsiField.class);
declaration = PsiTreeUtil.getParentOfType(place, HaxeFieldDeclaration.class);
}
return declaration;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
Expand All @@ -13,8 +12,6 @@
import com.intellij.plugins.haxe.lang.psi.HaxeForStatement;
import com.intellij.plugins.haxe.lang.psi.HaxePsiCompositeElement;
import com.intellij.plugins.haxe.lang.psi.HaxeReference;
import com.intellij.plugins.haxe.model.HaxeMemberModel;
import com.intellij.plugins.haxe.model.HaxeMethodModel;
import com.intellij.plugins.haxe.model.type.HaxeExpressionEvaluator;
import com.intellij.plugins.haxe.model.type.ResultHolder;
import com.intellij.plugins.haxe.model.type.SpecificHaxeClassReference;
Expand All @@ -24,19 +21,15 @@
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.introduce.inplace.InplaceVariableIntroducer;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;

public class IteratorForLoopIntention extends BaseIntentionAction {

private SpecificHaxeClassReference resolvedType;
private HaxeReference haxeReference;

public IteratorForLoopIntention() {
}
Expand All @@ -57,17 +50,19 @@ public String getText() {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (file.getLanguage() != HaxeLanguage.INSTANCE) return false;

return attemptToFindIterableExpression(editor, file);
HaxeReference reference = attemptToFindIterableExpression(editor, file);
return hasIterator(reference);
}


@Override
public void invoke(@NotNull final Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
HaxeForStatement itr = HaxeElementGenerator.createForInLoop(project, "itr", haxeReference.getText());
itr = (HaxeForStatement)haxeReference.replace(itr.copy());
HaxeReference reference = attemptToFindIterableExpression(editor, file);
if (reference != null) {
HaxeForStatement itr = HaxeElementGenerator.createForInLoop(project, "itr", reference.getText());
itr = (HaxeForStatement)reference.replace(itr.copy());

if (!editor.isViewer()) {
if (!editor.isViewer()) {
CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(itr);
HaxeComponentName name = itr.getComponentName();
final var introducer = new HaxeIntroduceHandler.HaxeInplaceVariableIntroducer(name, editor, List.of());
Expand All @@ -77,24 +72,25 @@ public void invoke(@NotNull final Project project, Editor editor, PsiFile file)
editor.getCaretModel().moveToOffset(range.getEndOffset());
introducer.performInplaceRefactoring(new LinkedHashSet<>(List.of()));
}
}
}


private boolean attemptToFindIterableExpression(Editor editor, PsiFile file) {
private HaxeReference attemptToFindIterableExpression(Editor editor, PsiFile file) {
PsiElement psiElement = file.findElementAt(editor.getCaretModel().getOffset());
if (psiElement instanceof PsiWhiteSpace) {
psiElement =
UsefulPsiTreeUtil.getPrevSiblingSkippingCondition(psiElement, element -> !(element instanceof HaxePsiCompositeElement), true);
psiElement = UsefulPsiTreeUtil.getPrevSiblingSkippingCondition(psiElement, element -> !(element instanceof HaxePsiCompositeElement), true);
}
if (psiElement == null) return false;
if (psiElement == null) return null;

haxeReference =
psiElement instanceof HaxeReference reference ? reference : PsiTreeUtil.getParentOfType(psiElement, HaxeReference.class);
return psiElement instanceof HaxeReference reference ? reference : PsiTreeUtil.getParentOfType(psiElement, HaxeReference.class);
}

if (haxeReference == null) return false;
private boolean hasIterator(HaxeReference reference) {
if (reference == null) return false;

ResultHolder holder = HaxeExpressionEvaluator.evaluate(haxeReference, null).result;
resolvedType = holder.getClassType();
ResultHolder holder = HaxeExpressionEvaluator.evaluate(reference, null).result;
SpecificHaxeClassReference resolvedType = holder.getClassType();
if (resolvedType == null) return false;

return resolvedType.isLiteralArray() || hasIterator(resolvedType);
Expand Down
Loading

0 comments on commit 3ed7971

Please sign in to comment.