From 4b720733c0ced842e56ac1286ba48a4bb150e623 Mon Sep 17 00:00:00 2001 From: svtk Date: Thu, 15 Sep 2011 20:17:09 +0400 Subject: [PATCH] Added AddAbstractModifierFix, renamed JetChangeUtil -> JetPsiFactory --- .../DiagnosticFactoryWithPsiElement1.java | 39 +++++++++ .../DiagnosticFactoryWithPsiElement2.java | 17 ++-- .../jet/lang/diagnostics/Errors.java | 7 +- .../ParameterizedDiagnosticFactory1.java | 21 +---- .../ParameterizedDiagnosticFactory2.java | 3 +- .../PsiElementOnlyDiagnosticFactory1.java | 15 ++++ .../PsiElementOnlyDiagnosticFactory2.java | 16 ++++ .../diagnostics/SimpleDiagnosticFactory.java | 15 +--- ...SimpleDiagnosticFactoryWithPsiElement.java | 28 +++++++ ...SimplePsiElementOnlyDiagnosticFactory.java | 19 +---- .../jet/lang/psi/JetNamedDeclaration.java | 2 +- ...{JetChangeUtil.java => JetPsiFactory.java} | 19 ++++- .../jet/lang/resolve/BodyResolver.java | 4 +- .../jet/plugin/annotations/JetPsiChecker.java | 3 +- .../quickfix/AddAbstractModifierFix.java | 83 +++++++++++++++++++ .../quickfix/IntentionActionFactory.java | 13 +++ .../IntentionActionForPsiElement.java | 16 ++++ .../jet/plugin/quickfix/QuickFixes.java | 19 +---- .../quickfix/RemoveAbstractModifierFix.java | 30 +++---- .../references/JetSimpleNameReference.java | 2 +- .../jet/types/JetOverridingTest.java | 4 +- .../jet/types/JetTypeCheckerTest.java | 12 +-- 22 files changed, 287 insertions(+), 100 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement1.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PsiElementOnlyDiagnosticFactory1.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PsiElementOnlyDiagnosticFactory2.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimpleDiagnosticFactoryWithPsiElement.java rename compiler/frontend/src/org/jetbrains/jet/lang/psi/{JetChangeUtil.java => JetPsiFactory.java} (74%) create mode 100644 idea/src/org/jetbrains/jet/plugin/quickfix/AddAbstractModifierFix.java create mode 100644 idea/src/org/jetbrains/jet/plugin/quickfix/IntentionActionFactory.java create mode 100644 idea/src/org/jetbrains/jet/plugin/quickfix/IntentionActionForPsiElement.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement1.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement1.java new file mode 100644 index 00000000000..efc03f41cdf --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement1.java @@ -0,0 +1,39 @@ +package org.jetbrains.jet.lang.diagnostics; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * @author svtk + */ +public abstract class DiagnosticFactoryWithPsiElement1 extends DiagnosticFactoryWithMessageFormat { + protected DiagnosticFactoryWithPsiElement1(Severity severity, String message) { + super(severity, message); + } + + protected String makeMessage(@NotNull A argument) { + return messageFormat.format(new Object[]{makeMessageFor(argument)}); + } + + protected String makeMessageFor(A argument) { + return argument.toString(); + } + + @NotNull + public Diagnostic on(@NotNull T element, @NotNull A argument) { + return on(element, element.getNode(), argument); + } + + @NotNull + public Diagnostic on(@NotNull T element, @NotNull ASTNode node, @NotNull A argument) { + return new DiagnosticWithPsiElement(this, severity, makeMessage(argument), element, node.getTextRange()); + } + + @NotNull + public Diagnostic on(@NotNull T element, @NotNull PsiElement psiElement, @NotNull A argument) { + return new DiagnosticWithPsiElement(this, severity, makeMessage(argument), element, psiElement.getTextRange()); + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement2.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement2.java index 23a459ab801..669090b4a50 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement2.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement2.java @@ -1,16 +1,14 @@ package org.jetbrains.jet.lang.diagnostics; +import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; + import org.jetbrains.annotations.NotNull; /** * @author abreslav */ -public class DiagnosticFactoryWithPsiElement2 extends DiagnosticFactoryWithMessageFormat { - - public static DiagnosticFactoryWithPsiElement2 create(Severity severity, String message) { - return new DiagnosticFactoryWithPsiElement2(severity, message); - } +public abstract class DiagnosticFactoryWithPsiElement2 extends DiagnosticFactoryWithMessageFormat { public DiagnosticFactoryWithPsiElement2(Severity severity, String message) { super(severity, message); @@ -29,7 +27,12 @@ public class DiagnosticFactoryWithPsiElement2 extends DiagnosticFactoryWit } @NotNull - public Diagnostic on(@NotNull PsiElement element, @NotNull A a, @NotNull B b) { - return new DiagnosticWithPsiElement(this, severity, makeMessage(a, b), element); + public Diagnostic on(@NotNull T element, @NotNull A a, @NotNull B b) { + return on(element, element.getNode(), a, b); + } + + @NotNull + public Diagnostic on(@NotNull T element, @NotNull ASTNode node, @NotNull A a, @NotNull B b) { + return new DiagnosticWithPsiElement(this, severity, makeMessage(a, b), element, node.getTextRange()); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index f5c3429414c..0a3919c9174 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.diagnostics; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; @@ -21,7 +22,7 @@ public interface Errors { UnresolvedReferenceDiagnosticFactory UNRESOLVED_REFERENCE = UnresolvedReferenceDiagnosticFactory.INSTANCE; RedeclarationDiagnosticFactory REDECLARATION = RedeclarationDiagnosticFactory.INSTANCE; - DiagnosticFactoryWithPsiElement2 TYPE_MISMATCH = DiagnosticFactoryWithPsiElement2.create(ERROR, "Type mismatch: inferred type is {1} but {0} was expected"); + PsiElementOnlyDiagnosticFactory2 TYPE_MISMATCH = PsiElementOnlyDiagnosticFactory2.create(ERROR, "Type mismatch: inferred type is {1} but {0} was expected"); SimpleDiagnosticFactory SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES = SimpleDiagnosticFactory.create(ERROR, "Safe calls are not allowed on namespaces"); SimpleDiagnosticFactory TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM = SimpleDiagnosticFactory.create(ERROR, "Type checking has run into a recursive problem"); // TODO: message @@ -54,10 +55,10 @@ public interface Errors { SimpleDiagnosticFactory PROPERTY_INITIALIZER_NO_BACKING_FIELD = SimpleDiagnosticFactory.create(ERROR, "Initializer is not allowed here because this property has no backing field"); SimpleDiagnosticFactory PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR, "Property initializers are not allowed when no primary constructor is present"); SimplePsiElementOnlyDiagnosticFactory REDUNDANT_ABSTRACT = SimplePsiElementOnlyDiagnosticFactory.create(WARNING, "Abstract modifier is redundant in traits"); - ParameterizedDiagnosticFactory2 ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS = ParameterizedDiagnosticFactory2.create(ERROR, "Abstract property {0} in non-abstract class {1}"); + PsiElementOnlyDiagnosticFactory2 ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS = PsiElementOnlyDiagnosticFactory2.create(ERROR, "Abstract property {0} in non-abstract class {1}"); ParameterizedDiagnosticFactory2 ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS = ParameterizedDiagnosticFactory2.create(ERROR, "Abstract function {0} in non-abstract class {1}"); ParameterizedDiagnosticFactory1 ABSTRACT_FUNCTION_WITH_BODY = ParameterizedDiagnosticFactory1.create(ERROR, "A function {0} with body cannot be abstract"); - ParameterizedDiagnosticFactory1 NON_ABSTRACT_FUNCTION_WITH_NO_BODY = ParameterizedDiagnosticFactory1.create(ERROR, "Method {0} without a body must be abstract"); + PsiElementOnlyDiagnosticFactory1 NON_ABSTRACT_FUNCTION_WITH_NO_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Method {0} without a body must be abstract"); ParameterizedDiagnosticFactory1 NON_MEMBER_ABSTRACT_FUNCTION = ParameterizedDiagnosticFactory1.create(ERROR, "Function {0} is not a class or trait member and cannot be abstract"); SimpleDiagnosticFactory NON_MEMBER_ABSTRACT_ACCESSOR = SimpleDiagnosticFactory.create(ERROR, "This property is not a class or trait member and thus cannot have abstract accessors"); // TODO : Better message ParameterizedDiagnosticFactory1 NON_MEMBER_FUNCTION_NO_BODY = ParameterizedDiagnosticFactory1.create(ERROR, "Function {0} must have a body"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/ParameterizedDiagnosticFactory1.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/ParameterizedDiagnosticFactory1.java index 311829a67d0..05a9de0c3df 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/ParameterizedDiagnosticFactory1.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/ParameterizedDiagnosticFactory1.java @@ -9,35 +9,22 @@ import org.jetbrains.annotations.NotNull; /** * @author abreslav */ -public class ParameterizedDiagnosticFactory1 extends DiagnosticFactoryWithMessageFormat { +public class ParameterizedDiagnosticFactory1 extends DiagnosticFactoryWithPsiElement1 { public static ParameterizedDiagnosticFactory1 create(Severity severity, String messageStub) { return new ParameterizedDiagnosticFactory1(severity, messageStub); } - public ParameterizedDiagnosticFactory1(Severity severity, String messageStub) { + protected ParameterizedDiagnosticFactory1(Severity severity, String messageStub) { super(severity, messageStub); } - private String makeMessage(@NotNull T argument) { - return messageFormat.format(new Object[]{makeMessageFor(argument)}); - } - - protected String makeMessageFor(T argument) { - return argument.toString(); - } - @NotNull - public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange range, @NotNull T argument) { + public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange range, @NotNull A argument) { return new GenericDiagnostic(this, severity, makeMessage(argument), psiFile, range); } @NotNull - public Diagnostic on(@NotNull ASTNode node, @NotNull T argument) { + public Diagnostic on(@NotNull ASTNode node, @NotNull A argument) { return on(DiagnosticUtils.getContainingFile(node), node.getTextRange(), argument); } - - @NotNull - public Diagnostic on(@NotNull PsiElement element, @NotNull T argument) { - return new DiagnosticWithPsiElement(this, severity, makeMessage(argument), element); - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/ParameterizedDiagnosticFactory2.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/ParameterizedDiagnosticFactory2.java index c30a9355c6b..eea8433558c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/ParameterizedDiagnosticFactory2.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/ParameterizedDiagnosticFactory2.java @@ -2,13 +2,14 @@ package org.jetbrains.jet.lang.diagnostics; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; /** * @author abreslav */ -public class ParameterizedDiagnosticFactory2 extends DiagnosticFactoryWithPsiElement2 { +public class ParameterizedDiagnosticFactory2 extends DiagnosticFactoryWithPsiElement2 { public static ParameterizedDiagnosticFactory2 create(Severity severity, String messageStub) { return new ParameterizedDiagnosticFactory2(severity, messageStub); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PsiElementOnlyDiagnosticFactory1.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PsiElementOnlyDiagnosticFactory1.java new file mode 100644 index 00000000000..3f5c6baee6b --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PsiElementOnlyDiagnosticFactory1.java @@ -0,0 +1,15 @@ +package org.jetbrains.jet.lang.diagnostics; + +import com.intellij.psi.PsiElement; +/** + * @author svtk + */ +public class PsiElementOnlyDiagnosticFactory1 extends DiagnosticFactoryWithPsiElement1 implements PsiElementOnlyDiagnosticFactory { + public static PsiElementOnlyDiagnosticFactory1 create(Severity severity, String messageStub) { + return new PsiElementOnlyDiagnosticFactory1(severity, messageStub); + } + + protected PsiElementOnlyDiagnosticFactory1(Severity severity, String message) { + super(severity, message); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PsiElementOnlyDiagnosticFactory2.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PsiElementOnlyDiagnosticFactory2.java new file mode 100644 index 00000000000..853e7841163 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PsiElementOnlyDiagnosticFactory2.java @@ -0,0 +1,16 @@ +package org.jetbrains.jet.lang.diagnostics; + +import com.intellij.psi.PsiElement; + +/** + * @author svtk + */ +public class PsiElementOnlyDiagnosticFactory2 extends DiagnosticFactoryWithPsiElement2 implements PsiElementOnlyDiagnosticFactory { + public static PsiElementOnlyDiagnosticFactory2 create(Severity severity, String messageStub) { + return new PsiElementOnlyDiagnosticFactory2(severity, messageStub); + } + + protected PsiElementOnlyDiagnosticFactory2(Severity severity, String message) { + super(severity, message); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimpleDiagnosticFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimpleDiagnosticFactory.java index e91b2349939..cd67cb5b670 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimpleDiagnosticFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimpleDiagnosticFactory.java @@ -9,17 +9,13 @@ import org.jetbrains.annotations.NotNull; /** * @author abreslav */ -public class SimpleDiagnosticFactory extends DiagnosticFactoryWithSeverity { - +public class SimpleDiagnosticFactory extends SimpleDiagnosticFactoryWithPsiElement { public static SimpleDiagnosticFactory create(Severity severity, String message) { return new SimpleDiagnosticFactory(severity, message); } - protected final String message; - - public SimpleDiagnosticFactory(Severity severity, String message) { - super(severity); - this.message = message; + protected SimpleDiagnosticFactory(Severity severity, String message) { + super(severity, message); } @NotNull @@ -31,9 +27,4 @@ public class SimpleDiagnosticFactory extends DiagnosticFactoryWithSeverity { public Diagnostic on(@NotNull ASTNode node) { return on(DiagnosticUtils.getContainingFile(node), node.getTextRange()); } - - @NotNull - public Diagnostic on(@NotNull PsiElement element) { - return new DiagnosticWithPsiElement(this, severity, message, element); - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimpleDiagnosticFactoryWithPsiElement.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimpleDiagnosticFactoryWithPsiElement.java new file mode 100644 index 00000000000..4d8a7d4b7ee --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimpleDiagnosticFactoryWithPsiElement.java @@ -0,0 +1,28 @@ +package org.jetbrains.jet.lang.diagnostics; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +/** + * @author svtk + */ +public abstract class SimpleDiagnosticFactoryWithPsiElement extends DiagnosticFactoryWithSeverity { + + protected final String message; + + protected SimpleDiagnosticFactoryWithPsiElement(Severity severity, String message) { + super(severity); + this.message = message; + } + + @NotNull + public Diagnostic on(@NotNull T element, @NotNull ASTNode node) { + return new DiagnosticWithPsiElement(this, severity, message, element, node.getTextRange()); + } + + @NotNull + public Diagnostic on(@NotNull T element) { + return on(element, element.getNode()); + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimplePsiElementOnlyDiagnosticFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimplePsiElementOnlyDiagnosticFactory.java index 63ff839fe0c..bfc73838a45 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimplePsiElementOnlyDiagnosticFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/SimplePsiElementOnlyDiagnosticFactory.java @@ -9,26 +9,13 @@ import org.jetbrains.annotations.NotNull; /** * @author svtk */ -public class SimplePsiElementOnlyDiagnosticFactory extends DiagnosticFactoryWithSeverity implements PsiElementOnlyDiagnosticFactory { +public class SimplePsiElementOnlyDiagnosticFactory extends SimpleDiagnosticFactoryWithPsiElement implements PsiElementOnlyDiagnosticFactory { public static SimplePsiElementOnlyDiagnosticFactory create(Severity severity, String message) { return new SimplePsiElementOnlyDiagnosticFactory(severity, message); } - protected final String message; - - public SimplePsiElementOnlyDiagnosticFactory(Severity severity, String message) { - super(severity); - this.message = message; - } - - @NotNull - public Diagnostic on(@NotNull T element, @NotNull ASTNode node) { - return new DiagnosticWithPsiElement(this, severity, message, element, node.getTextRange()); - } - - @NotNull - public Diagnostic on(@NotNull T element) { - return on(element, element.getNode()); + protected SimplePsiElementOnlyDiagnosticFactory(Severity severity, String message) { + super(severity, message); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedDeclaration.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedDeclaration.java index d6a5caa149c..f80a390fc75 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedDeclaration.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedDeclaration.java @@ -29,7 +29,7 @@ public abstract class JetNamedDeclaration extends JetDeclaration implements PsiN @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { - return getNameIdentifier().replace(JetChangeUtil.createNameIdentifier(getProject(), name)); + return getNameIdentifier().replace(JetPsiFactory.createNameIdentifier(getProject(), name)); } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetChangeUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java similarity index 74% rename from compiler/frontend/src/org/jetbrains/jet/lang/psi/JetChangeUtil.java rename to compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java index 6cbe9f35289..e58d0e51878 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetChangeUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java @@ -5,6 +5,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFileFactory; import com.intellij.util.LocalTimeCounter; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.plugin.JetFileType; import java.util.List; @@ -12,7 +13,7 @@ import java.util.List; /** * @author max */ -public class JetChangeUtil { +public class JetPsiFactory { public static JetExpression createExpression(Project project, String text) { JetProperty property = createProperty(project, "val x = " + text); return property.getInitializer(); @@ -23,6 +24,16 @@ public class JetChangeUtil { return property.getPropertyTypeRef(); } + public static PsiElement[] createColon(Project project) { + JetProperty property = createProperty(project, "val x : Int"); + return new PsiElement[] { property.findElementAt(5), property.findElementAt(6), property.findElementAt(7) }; + } + + public static PsiElement createWhiteSpace(Project project) { + JetProperty property = createProperty(project, "val x"); + return property.findElementAt(3); + } + public static JetClass createClass(Project project, String text) { return createDeclaration(project, text, JetClass.class); } @@ -58,4 +69,10 @@ public class JetChangeUtil { public static JetNamedFunction createFunction(Project project, String funDecl) { return createDeclaration(project, funDecl, JetNamedFunction.class); } + + public static JetModifierList createModifier(Project project, JetKeywordToken modifier) { + String text = modifier.getValue() + " val x"; + JetProperty property = createProperty(project, text); + return property.getModifierList(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 2d36d49885c..2da0eb2866b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -616,7 +616,7 @@ public class BodyResolver { } if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) { // context.getTrace().getErrorHandler().genericError(abstractNode, "Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName()); - context.getTrace().report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(abstractNode, property.getName(), classDescriptor)); + context.getTrace().report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, abstractNode, property.getName(), classDescriptor)); return; } if (classDescriptor.getKind() == ClassKind.TRAIT) { @@ -804,7 +804,7 @@ public class BodyResolver { } if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null && !isPropertyAccessor) { // context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Method " + function.getName() + " without body must be abstract"); - context.getTrace().report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(nameIdentifier, functionDescriptor)); + context.getTrace().report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(modifierListOwner, nameIdentifier, functionDescriptor)); } return; } diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java index 87d2240d560..02bf994dfba 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java @@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.AnalyzerFacade; import org.jetbrains.jet.plugin.JetHighlighter; +import org.jetbrains.jet.plugin.quickfix.IntentionActionFactory; import org.jetbrains.jet.plugin.quickfix.QuickFixes; import java.util.Collection; @@ -85,7 +86,7 @@ public class JetPsiChecker implements Annotator { DiagnosticWithPsiElement diagnosticWithPsiElement = (DiagnosticWithPsiElement) diagnostic; if (diagnostic.getFactory() instanceof PsiElementOnlyDiagnosticFactory) { PsiElementOnlyDiagnosticFactory factory = (PsiElementOnlyDiagnosticFactory) diagnostic.getFactory(); - QuickFixes.IntentionActionFactory intentionActionFactory = QuickFixes.get(factory); + IntentionActionFactory intentionActionFactory = QuickFixes.get(factory); IntentionAction action = null; if (intentionActionFactory != null) { action = intentionActionFactory.createAction(diagnosticWithPsiElement); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddAbstractModifierFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddAbstractModifierFix.java new file mode 100644 index 00000000000..566288e9849 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddAbstractModifierFix.java @@ -0,0 +1,83 @@ +package org.jetbrains.jet.plugin.quickfix; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lexer.JetTokens; + +/** + * @author svtk + */ +public class AddAbstractModifierFix extends IntentionActionForPsiElement { + + public AddAbstractModifierFix(@NotNull JetModifierListOwner element) { + super(element); + } + + @NotNull + @Override + public String getText() { + return "add.abstract.modifier.fix"; + } + + @NotNull + @Override + public String getFamilyName() { + return "add.abstract.modifier.family"; + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return element.isValid() && !element.hasModifier(JetTokens.FINAL_KEYWORD); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + element.replace(addAbstractModifier(element, project)); + } + + @NotNull + public static JetModifierListOwner addAbstractModifier(@NotNull PsiElement element, @NotNull Project project) { + JetModifierListOwner newElement = (JetModifierListOwner) (element.copy()); + + JetModifierList modifierList = newElement.getModifierList(); + JetModifierList listWithModifier = JetPsiFactory.createModifier(project, JetTokens.ABSTRACT_KEYWORD); + PsiElement whiteSpace = JetPsiFactory.createWhiteSpace(project); + if (modifierList == null) { + PsiElement firstChild = newElement.getFirstChild(); + newElement.addBefore(listWithModifier, firstChild); + newElement.addBefore(whiteSpace, firstChild); + } + else if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) { + PsiElement openModifierPsi = modifierList.getModifierNode(JetTokens.OPEN_KEYWORD).getPsi(); + assert openModifierPsi != null; + openModifierPsi.replace(listWithModifier.getFirstChild()); + } + else { + PsiElement lastChild = modifierList.getLastChild(); + modifierList.addAfter(listWithModifier.getFirstChild(), lastChild); + modifierList.addAfter(whiteSpace, lastChild); + } + return newElement; + } + + @Override + public boolean startInWriteAction() { + return true; + } + + public static IntentionActionFactory factory = + new IntentionActionFactory() { + @Override + public IntentionActionForPsiElement createAction(DiagnosticWithPsiElement diagnostic) { + assert diagnostic.getPsiElement() instanceof JetModifierListOwner; + return new AddAbstractModifierFix((JetModifierListOwner) diagnostic.getPsiElement()); + } + }; +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/IntentionActionFactory.java b/idea/src/org/jetbrains/jet/plugin/quickfix/IntentionActionFactory.java new file mode 100644 index 00000000000..aa50303a0c2 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/IntentionActionFactory.java @@ -0,0 +1,13 @@ +package org.jetbrains.jet.plugin.quickfix; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; + +/** +* @author svtk +*/ +public interface IntentionActionFactory { + + IntentionActionForPsiElement createAction(DiagnosticWithPsiElement diagnostic); + +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/IntentionActionForPsiElement.java b/idea/src/org/jetbrains/jet/plugin/quickfix/IntentionActionForPsiElement.java new file mode 100644 index 00000000000..d7c9649333d --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/IntentionActionForPsiElement.java @@ -0,0 +1,16 @@ +package org.jetbrains.jet.plugin.quickfix; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +/** +* @author svtk +*/ +public abstract class IntentionActionForPsiElement implements IntentionAction { + protected @NotNull T element; + + public IntentionActionForPsiElement(@NotNull T element) { + this.element = element; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java index 5808ef7ee6a..af8a30706af 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java @@ -3,7 +3,6 @@ package org.jetbrains.jet.plugin.quickfix; import com.google.common.collect.Maps; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.psi.PsiElement; -import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.diagnostics.PsiElementOnlyDiagnosticFactory; @@ -15,24 +14,12 @@ import java.util.Map; public class QuickFixes { private static Map actionMap = Maps.newHashMap(); - public static IntentionActionFactory get(PsiElementOnlyDiagnosticFactory f) { - return actionMap.get(f); + public static IntentionActionFactory get(PsiElementOnlyDiagnosticFactory diagnosticFactory) { + return actionMap.get(diagnosticFactory); } private QuickFixes() {} - public static abstract class IntentionActionForPsiElement implements IntentionAction { - protected T psiElement; - - public IntentionActionForPsiElement(T element) { - this.psiElement = element; - } - } - - public interface IntentionActionFactory { - IntentionActionForPsiElement createAction(DiagnosticWithPsiElement diagnostic); - } - private static void add(PsiElementOnlyDiagnosticFactory diagnosticFactory, IntentionActionFactory actionFactory) { actionMap.put(diagnosticFactory, actionFactory); } @@ -40,6 +27,8 @@ public class QuickFixes { static { add(Errors.REDUNDANT_ABSTRACT, RemoveAbstractModifierFix.factory); + add(Errors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS, RemoveAbstractModifierFix.factory); + add(Errors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY, AddAbstractModifierFix.factory); } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveAbstractModifierFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveAbstractModifierFix.java index aee9cf8238c..0b55d4e4fb9 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveAbstractModifierFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveAbstractModifierFix.java @@ -9,14 +9,15 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetModifierListOwner; import org.jetbrains.jet.lexer.JetTokens; /** * @author svtk */ -public class RemoveAbstractModifierFix extends QuickFixes.IntentionActionForPsiElement { - public RemoveAbstractModifierFix(JetModifierListOwner element) { +public class RemoveAbstractModifierFix extends IntentionActionForPsiElement { + public RemoveAbstractModifierFix(@NotNull JetModifierListOwner element) { super(element); } @@ -34,22 +35,21 @@ public class RemoveAbstractModifierFix extends QuickFixes.IntentionActionForPsiE @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return psiElement.isValid(); + return element.isValid(); } @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - JetDeclaration declaration = removeAbstractModifier(psiElement); - psiElement.replace(declaration); + element.replace(removeAbstractModifier(element)); } - public static JetDeclaration removeAbstractModifier(PsiElement element) { - assert element instanceof JetDeclaration; - JetDeclaration declaration = (JetDeclaration) (element.copy()); - assert declaration.hasModifier(JetTokens.ABSTRACT_KEYWORD); - ASTNode abstractNode = declaration.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD); - declaration.deleteChildInternal(abstractNode); - return declaration; + @NotNull + public static JetModifierListOwner removeAbstractModifier(PsiElement element) { + JetModifierListOwner newElement = (JetModifierListOwner) (element.copy()); + assert newElement.hasModifier(JetTokens.ABSTRACT_KEYWORD); + ASTNode abstractNode = newElement.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD); + ((JetElement)newElement).deleteChildInternal(abstractNode); + return newElement; } @Override @@ -57,10 +57,10 @@ public class RemoveAbstractModifierFix extends QuickFixes.IntentionActionForPsiE return true; } - public static QuickFixes.IntentionActionFactory factory = - new QuickFixes.IntentionActionFactory() { + public static IntentionActionFactory factory = + new IntentionActionFactory() { @Override - public QuickFixes.IntentionActionForPsiElement createAction(DiagnosticWithPsiElement diagnostic) { + public IntentionActionForPsiElement createAction(DiagnosticWithPsiElement diagnostic) { assert diagnostic.getPsiElement() instanceof JetModifierListOwner; return new RemoveAbstractModifierFix((JetModifierListOwner) diagnostic.getPsiElement()); } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index f6e7f7e6d57..7896d7bcf63 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -69,7 +69,7 @@ class JetSimpleNameReference extends JetPsiReference { @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { - PsiElement element = JetChangeUtil.createNameIdentifier(myExpression.getProject(), newElementName); + PsiElement element = JetPsiFactory.createNameIdentifier(myExpression.getProject(), newElementName); return myExpression.getReferencedNameElement().replace(element); } diff --git a/idea/tests/org/jetbrains/jet/types/JetOverridingTest.java b/idea/tests/org/jetbrains/jet/types/JetOverridingTest.java index 2c6bfc6502e..13d0c1a8827 100644 --- a/idea/tests/org/jetbrains/jet/types/JetOverridingTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetOverridingTest.java @@ -7,7 +7,7 @@ import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptorUtil; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.psi.JetChangeUtil; +import org.jetbrains.jet.lang.psi.JetPsiFactory; import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver; import org.jetbrains.jet.lang.types.*; @@ -144,7 +144,7 @@ public class JetOverridingTest extends LightDaemonAnalyzerTestCase { } private FunctionDescriptor makeFunction(String funDecl) { - JetNamedFunction function = JetChangeUtil.createFunction(getProject(), funDecl); + JetNamedFunction function = JetPsiFactory.createFunction(getProject(), funDecl); return classDescriptorResolver.resolveFunctionDescriptor(root, library.getLibraryScope(), function); } } diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 60dffcf3152..2b2cee7886a 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -490,14 +490,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { private void assertType(String expression, JetType expectedType) { Project project = getProject(); - JetExpression jetExpression = JetChangeUtil.createExpression(project, expression); + JetExpression jetExpression = JetPsiFactory.createExpression(project, expression); JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE, JetFlowInformationProvider.NONE).getType(scopeWithImports, jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); assertTrue(type + " != " + expectedType, type.equals(expectedType)); } private void assertErrorType(String expression) { Project project = getProject(); - JetExpression jetExpression = JetChangeUtil.createExpression(project, expression); + JetExpression jetExpression = JetPsiFactory.createExpression(project, expression); JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE, JetFlowInformationProvider.NONE).safeGetType(scopeWithImports, jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type)); } @@ -520,7 +520,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { private void assertType(JetScope scope, String expression, String expectedTypeStr) { Project project = getProject(); - JetExpression jetExpression = JetChangeUtil.createExpression(project, expression); + JetExpression jetExpression = JetPsiFactory.createExpression(project, expression); JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE, JetFlowInformationProvider.NONE).getType(addImports(scope), jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr); assertEquals(expectedType, type); @@ -540,7 +540,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { } private JetType makeType(JetScope scope, String typeStr) { - return new TypeResolver(semanticServices, JetTestUtils.DUMMY_TRACE, true).resolveType(scope, JetChangeUtil.createType(getProject(), typeStr)); + return new TypeResolver(semanticServices, JetTestUtils.DUMMY_TRACE, true).resolveType(scope, JetPsiFactory.createType(getProject(), typeStr)); } @Override @@ -594,7 +594,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { public ClassifierDescriptor getClassifier(@NotNull String name) { if (CLASSES.isEmpty()) { for (String classDeclaration : CLASS_DECLARATIONS) { - JetClass classElement = JetChangeUtil.createClass(getProject(), classDeclaration); + JetClass classElement = JetPsiFactory.createClass(getProject(), classDeclaration); ClassDescriptor classDescriptor = resolveClassDescriptor(this, classElement); CLASSES.put(classDescriptor.getName(), classDescriptor); } @@ -617,7 +617,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { // } ModuleDescriptor module = new ModuleDescriptor("TypeCheckerTest"); for (String funDecl : FUNCTION_DECLARATIONS) { - FunctionDescriptor functionDescriptor = classDescriptorResolver.resolveFunctionDescriptor(module, this, JetChangeUtil.createFunction(getProject(), funDecl)); + FunctionDescriptor functionDescriptor = classDescriptorResolver.resolveFunctionDescriptor(module, this, JetPsiFactory.createFunction(getProject(), funDecl)); if (name.equals(functionDescriptor.getName())) { writableFunctionGroup.addFunction(functionDescriptor); }