Merge branch master into pr/269

This commit is contained in:
Evgeny Gerashchenko
2013-06-10 17:40:27 +04:00
1342 changed files with 39789 additions and 2594 deletions
@@ -1,11 +0,0 @@
public class MyClass {
public fun f(a: Int): String {
var res: String
if (a == 1) res = "one";
else if (a == 2) res = "two";
else res = "too many";
return res;
}
}
@@ -1,11 +0,0 @@
public class MyClass {
public fun f(a: Int): String {
var res: String
res = if (a == 1) "one";
else if (a == 2) "two";
else "too many";
return res;
}
}
@@ -1,6 +0,0 @@
<html>
<body>
This intention converts assignment with 'if' expression as right-hand side
into 'if' statement where each branch is terminated with assignment to the original variable
</body>
</html>
@@ -0,0 +1,11 @@
when {
n == 1 -> {
res = "one"
}
n == 2 -> {
res = "two"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,11 @@
when (n) {
1 -> {
res = "one"
}
2 -> {
res = "two"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention eliminates argument of 'when' expression transforming its pattern-matching conditions into boolean expressions
</body>
</html>
@@ -0,0 +1,17 @@
when (n) {
1 -> {
res = "one"
}
2 -> {
res = "two"
}
3 -> {
res = "three"
}
4 -> {
res = "four"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,19 @@
when (n) {
1 -> {
res = "one"
}
2 -> {
res = "two"
}
else -> when (n) {
3 -> {
res = "thress"
}
4 -> {
res = "four"
}
else -> {
res = "???"
}
}
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention merges branches of nested 'when' expression into enclosing one
</body>
</html>
@@ -0,0 +1,5 @@
res = if (ok) {
"ok"
} else {
"failed"
}
@@ -0,0 +1,5 @@
if (ok) {
res = "ok"
} else {
res = "failed"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'if' expression where each branch is terminated with assignment into a single assignment with 'if' expression as a right-hand side
</body>
</html>
@@ -0,0 +1,4 @@
if (ok) {
return "ok"
}
return "failed"
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts single-branch 'if' expression immediately followed by 'return' into a single 'return' with 'if' expression as an argument
</body>
</html>
@@ -0,0 +1,5 @@
return if (ok) {
"ok"
} else {
"failed"
}
@@ -0,0 +1,5 @@
if (ok) {
return "ok"
} else {
return "failed"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'if' expression where each branch is terminated with 'return' into a single 'return' with 'if' expression as a right-hand side
</body>
</html>
@@ -0,0 +1,5 @@
res = when (n) {
1 -> "one"
2 -> "two"
else -> "many"
}
@@ -0,0 +1,5 @@
when (n) {
1 -> res = "one"
2 -> res = "two"
else -> res = "many"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'when' expression where each branch is terminated with assignment into a single assignment with 'when' expression as right-hand side
</body>
</html>
@@ -0,0 +1,5 @@
return when (n) {
1 -> "one"
2 -> "two"
else -> "many"
}
@@ -0,0 +1,5 @@
when (n) {
1 -> return "one"
2 -> return "two"
else -> return "many"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'when' expression where each branch is terminated with 'return' into a single 'return' with 'when' expression as a right-hand side
</body>
</html>
@@ -1,11 +0,0 @@
public class MyClass {
public fun f(a: Int): String {
var res: String
res = if (a == 1) "one";
else if (a == 2) "two";
else "too many";
return res;
}
}
@@ -1,11 +0,0 @@
public class MyClass {
public fun f(a: Int): String {
var res: String
if (a == 1) res = "one";
else if (a == 2) res = "two";
else res = "too many";
return res;
}
}
@@ -1,6 +0,0 @@
<html>
<body>
This intention converts 'if' statement where each branch is terminated with assignment to the same variable
into single assignment with 'if' expression
</body>
</html>
@@ -0,0 +1,11 @@
when (n) {
1 -> {
res = "one"
}
2 -> {
res = "two"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,7 @@
if (n == 1) {
res = "one"
} else if (n == 2) {
res = "two"
} else {
res = "???"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'if' expression to equivalent 'when' expression
</body>
</html>
@@ -0,0 +1,11 @@
when (n) {
1 -> {
res = "one"
}
2 -> {
res = "two"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,11 @@
when {
n == 1 -> {
res = "one"
}
n == 2 -> {
res = "two"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention introduces argument into 'when' expression simplifying conditions of its branches
</body>
</html>
@@ -0,0 +1,5 @@
if (ok) {
res = "ok"
} else {
res = "failed"
}
@@ -0,0 +1,5 @@
res = if (ok) {
"ok"
} else {
"failed"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts assignment with 'if' right-hand side to 'if' expression where each branch is terminated with assignment
</body>
</html>
@@ -0,0 +1,5 @@
when (n) {
1 -> res = "one"
2 -> res = "two"
else -> res = "many"
}
@@ -0,0 +1,5 @@
res = when (n) {
1 -> "one"
2 -> "two"
else -> "many"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts assignment with 'when' right-hand side to 'when' expression where each branch is terminated with assignment
</body>
</html>
@@ -0,0 +1,6 @@
val res: String
if (ok) {
res = "ok"
} else {
res = "failed"
}
@@ -0,0 +1,5 @@
val res = if (ok) {
"ok"
} else {
"failed"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts property with 'if' initializer to uninitialized property followed by 'if' expression where each branch is terminated with assignment
</body>
</html>
@@ -0,0 +1,6 @@
val res: String
when (n) {
1 -> res = "one"
2 -> res = "two"
else -> res = "many"
}
@@ -0,0 +1,5 @@
val res = when (n) {
1 -> "one"
2 -> "two"
else -> "many"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts property with 'when' initializer to uninitialized property followed by 'when' expression where each branch is terminated with assignment
</body>
</html>
@@ -0,0 +1,5 @@
if (ok) {
return "ok"
} else {
return "failed"
}
@@ -0,0 +1,5 @@
return if (ok) {
"ok"
} else {
"failed"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'return' with 'if' expression as a result to 'if' expression where each branch is terminated with 'return'
</body>
</html>
@@ -0,0 +1,5 @@
when (n) {
1 -> return "one"
2 -> return "two"
else -> return "many"
}
@@ -0,0 +1,5 @@
return when (n) {
1 -> "one"
2 -> "two"
else -> "many"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'return' with 'when' expression as a result to 'when' expression where each branch is terminated with 'return'
</body>
</html>
@@ -0,0 +1,7 @@
if (n == 1) {
res = "one"
} else if (n == 2) {
res = "two"
} else {
res = "???"
}
@@ -0,0 +1,11 @@
when (n) {
1 -> {
res = "one"
}
2 -> {
res = "two"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'when' expression to one or more 'if' expressions
</body>
</html>
+82 -2
View File
@@ -219,6 +219,8 @@
forClass="org.jetbrains.jet.lang.psi.JetClass"/>
<itemPresentationProvider implementationClass="org.jetbrains.jet.plugin.presentation.JetPropertyPresenter"
forClass="org.jetbrains.jet.lang.psi.JetProperty"/>
<itemPresentationProvider implementationClass="org.jetbrains.jet.plugin.presentation.JetParameterPresenter"
forClass="org.jetbrains.jet.lang.psi.JetParameter"/>
<gotoTargetRendererProvider id="JetGotoTargetRenderProvider" implementation="org.jetbrains.jet.plugin.JetGotoTargetRenderProvider"
order="first"/>
<elementDescriptionProvider implementation="org.jetbrains.jet.plugin.findUsages.JetElementDescriptionProvider"/>
@@ -281,6 +283,14 @@
serviceImplementation="org.jetbrains.jet.plugin.editor.JetEditorOptions"/>
<editorAppearanceConfigurable instance="org.jetbrains.jet.plugin.editor.JetSettingEditorConfigurable"/>
<statementUpDownMover id="jetExpression"
implementation="org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover"
order="before declaration" />
<statementUpDownMover id="jetDeclaration"
implementation="org.jetbrains.jet.plugin.codeInsight.upDownMover.JetDeclarationMover"
order="before jetExpression" />
<intentionAction>
<className>org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction</className>
<category>Kotlin</category>
@@ -292,12 +302,82 @@
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.IfStatementWithAssignmentsToExpressionIntention</className>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.FoldBranchedExpressionIntention$FoldIfToAssignmentIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.AssignmentWithIfExpressionToStatementIntention</className>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.FoldBranchedExpressionIntention$FoldIfToReturnAsymmetricallyIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.FoldBranchedExpressionIntention$FoldIfToReturnIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.FoldBranchedExpressionIntention$FoldWhenToAssignmentIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.FoldBranchedExpressionIntention$FoldWhenToReturnIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.UnfoldBranchedExpressionIntention$UnfoldAssignmentToIfIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.UnfoldBranchedExpressionIntention$UnfoldPropertyToIfIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.UnfoldBranchedExpressionIntention$UnfoldAssignmentToWhenIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.UnfoldBranchedExpressionIntention$UnfoldPropertyToWhenIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.UnfoldBranchedExpressionIntention$UnfoldReturnToIfIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.UnfoldBranchedExpressionIntention$UnfoldReturnToWhenIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.IfToWhenIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.WhenToIfIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.FlattenWhenIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.IntroduceWhenSubjectIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions.EliminateWhenSubjectIntention</className>
<category>Kotlin</category>
</intentionAction>
@@ -59,9 +59,12 @@ add.semicolon.after.invocation=Add semicolon after invocation of ''{0}''
add.semicolon.family=Add Semicolon
change.function.return.type=Change ''{0}'' function return type to ''{1}''
change.no.name.function.return.type=Change function return type to ''{0}''
change.function.literal.return.type=Change function literal return type to ''{0}''
remove.function.return.type=Remove explicitly specified return type in ''{0}'' function
remove.no.name.function.return.type=Remove explicitly specified function return type
change.element.type=Change ''{0}'' type to ''{1}''
change.function.parameter.type=Change parameter ''{0}'' type of function ''{1}'' to ''{2}''
change.primary.constructor.parameter.type=Change parameter ''{0}'' type of primary constructor of class ''{1}'' to ''{2}''
change.type=Change type from ''{0}'' to ''{1}''
change.type.family=Change Type
add.parameters.to.function=Add parameter{0} to function ''{1}''
@@ -110,6 +113,8 @@ options.jet.attribute.descriptor.closure.braces=Function literal braces and arro
options.jet.attribute.descriptor.safe.access=Safe access dot
options.jet.attribute.descriptor.arrow=Arrow
options.jet.attribute.descriptor.kdoc.comment=KDoc comment
options.jet.attribute.descriptor.kdoc.tag=KDoc tag
options.jet.attribute.descriptor.kdoc.value=KDoc tag value
options.jet.attribute.descriptor.trait=Trait
options.jet.attribute.descriptor.annotation=Annotation
options.jet.attribute.descriptor.var=Var (mutable variable, parameter or property)
@@ -154,6 +159,44 @@ surround.with.cannot.perform.action=Cannot perform Surround With action to the c
remove.variable.family.name=Remove variable
remove.variable.action=Remove variable ''{0}''
kotlin.code.transformations=Kotlin Code Transformations
fold.if.to.assignment=Replace 'if' expression with assignment
fold.if.to.assignment.family=Replace 'if' Expression with Assignment
fold.if.to.return=Replace 'if' expression with return
fold.if.to.return.family=Replace 'if' Expression with Return
fold.if.to.call=Replace 'if' expression with method call
fold.if.to.call.family=Replace 'if' Expression with Method Call
fold.when.to.assignment=Replace 'when' expression with assignment
fold.when.to.assignment.family=Replace 'when' Expression with Assignment
fold.when.to.return=Replace 'when' expression with return
fold.when.to.return.family=Replace 'when' Expression with Return
fold.when.to.call=Replace 'when' expression with method call
fold.when.to.call.family=Replace 'when' Expression with Method Call
unfold.assignment.to.if=Replace assignment with 'if' expression
unfold.assignment.to.if.family=Replace Assignment with 'if' Expression
unfold.property.to.if=Replace property initializer with 'if' expression
unfold.property.to.if.family=Replace Property Initializer with 'if' Expression
unfold.return.to.if=Replace return with 'if' expression
unfold.return.to.if.family=Replace Return with 'if' Expression
unfold.call.to.if=Replace method call with 'if' expression
unfold.call.to.if.family=Replace Method Call with 'if' Expression
unfold.assignment.to.when=Replace assignment with 'when' expression
unfold.assignment.to.when.family=Replace Assignment with 'when' Expression
unfold.property.to.when=Replace property initializer with 'when' expression
unfold.property.to.when.family=Replace Property Initializer with 'when' Expression
unfold.return.to.when=Replace return with 'when' expression
unfold.return.to.when.family=Replace Return with 'when' Expression
unfold.call.to.when=Replace method call with 'when' expression
unfold.call.to.when.family=Replace Method Call with 'when' Expression
if.to.when=Replace 'if' with 'when'
if.to.when.family=Replace 'if' with 'when'
when.to.if=Replace 'when' with 'if'
when.to.if.family=Replace 'when' with 'if'
flatten.when=Flatten 'when' expression
flatten.when.family=Flatten 'when' Expression
introduce.when.subject=Introduce argument to 'when'
introduce.when.subject.family=Introduce Argument to 'when'
eliminate.when.subject=Eliminate argument of 'when'
eliminate.when.subject.family=Eliminate Argument of 'when'
transform.if.statement.with.assignments.to.expression=Transform 'if' statement with assignments to expression
transform.assignment.with.if.expression.to.statement=Transform assignment with 'if' expression to statement
transform.if.statement.with.assignments.to.expression.family=Transform 'if' Statement with Assignments to Expression
@@ -164,4 +207,22 @@ change.function.signature.family=Change function signature
change.function.signature.chooser.title=Choose signature
change.function.signature.action=Change function signature
remove.unnecessary.parentheses=Remove unnecessary parentheses
remove.unnecessary.parentheses.family=Remove Unnecessary Parentheses
remove.unnecessary.parentheses.family=Remove Unnecessary Parentheses
add.name.to.argument.family=Add Name to Argument
add.name.to.argument.single=Add name to argument\: ''{0}''
add.name.to.argument.multiple=Add name to argument...
add.name.to.argument.action=Add name to argument...
add.name.to.parameter.name.chooser.title=Choose parameter name
property.is.implemented.too.many=Has implementations
property.is.overridden.too.many=Is overridden in subclasses
property.is.implemented.header=Is implemented in <br/>
property.is.overridden.header=Is overridden in <br/>
navigation.title.overriding.property=Choose Implementation of {0}
navigation.findUsages.title.overriding.property=Overriding properties of {0}
add.function.to.supertype.family=Add Function to Supertype
add.function.to.supertype.action.multiple=Add function to supertype...
add.function.to.type.action.single=Add ''{0}'' to ''{1}''
add.function.to.type.action=Add function to type
add.function.to.type.action.type.chooser=Choose type...
@@ -16,9 +16,13 @@
package org.jetbrains.jet.plugin;
import com.intellij.lang.Commenter;
import com.intellij.lang.CodeDocumentationAwareCommenter;
import com.intellij.psi.PsiComment;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.jet.kdoc.psi.api.KDoc;
import org.jetbrains.jet.lexer.JetTokens;
public class JetCommenter implements Commenter {
public class JetCommenter implements CodeDocumentationAwareCommenter {
@Override
public String getLineCommentPrefix() {
return "//";
@@ -43,4 +47,39 @@ public class JetCommenter implements Commenter {
public String getCommentedBlockCommentSuffix() {
return null;
}
@Override
public IElementType getLineCommentTokenType() {
return JetTokens.EOL_COMMENT;
}
@Override
public IElementType getBlockCommentTokenType() {
return JetTokens.BLOCK_COMMENT;
}
@Override
public IElementType getDocumentationCommentTokenType() {
return JetTokens.DOC_COMMENT;
}
@Override
public String getDocumentationCommentPrefix() {
return "/**";
}
@Override
public String getDocumentationCommentLinePrefix() {
return "*";
}
@Override
public String getDocumentationCommentSuffix() {
return "*/";
}
@Override
public boolean isDocumentationComment(PsiComment element) {
return element instanceof KDoc;
}
}
@@ -143,12 +143,10 @@ public class JetIconProvider extends IconProvider {
}
if (psiElement instanceof JetParameter) {
JetParameter parameter = (JetParameter) psiElement;
if (parameter.getValOrVarNode() != null) {
JetParameterList parameterList = PsiTreeUtil.getParentOfType(psiElement, JetParameterList.class);
if (parameterList != null && parameterList.getParent() instanceof JetClass) {
return parameter.isMutable() ? JetIcons.FIELD_VAR : JetIcons.FIELD_VAL;
}
if (JetPsiUtil.getClassIfParameterIsProperty(parameter) != null) {
return parameter.isMutable() ? JetIcons.FIELD_VAR : JetIcons.FIELD_VAL;
}
return JetIcons.PARAMETER;
}
if (psiElement instanceof JetProperty) {
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.kdoc.lexer.KDocTokens;
import org.jetbrains.jet.lexer.JetTokens;
public class JetPairMatcher implements PairedBraceMatcher {
@@ -29,7 +30,8 @@ public class JetPairMatcher implements PairedBraceMatcher {
new BracePair(JetTokens.LPAR, JetTokens.RPAR, false),
new BracePair(JetTokens.LONG_TEMPLATE_ENTRY_START, JetTokens.LONG_TEMPLATE_ENTRY_END, false),
new BracePair(JetTokens.LBRACE, JetTokens.RBRACE, true),
new BracePair(JetTokens.LBRACKET, JetTokens.RBRACKET, false)
new BracePair(JetTokens.LBRACKET, JetTokens.RBRACKET, false),
new BracePair(KDocTokens.WIKI_LINK_OPEN, KDocTokens.WIKI_LINK_CLOSE, false)
};
@Override
@@ -39,7 +41,14 @@ public class JetPairMatcher implements PairedBraceMatcher {
@Override
public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) {
return JetTokens.WHITE_SPACE_OR_COMMENT_BIT_SET.contains(contextType)
if (lbraceType.equals(JetTokens.LONG_TEMPLATE_ENTRY_START)) {
// KotlinTypedHandler insert paired brace in this case
return false;
}
if (lbraceType == KDocTokens.WIKI_LINK_OPEN) return false;
return JetTokens.WHITE_SPACE_OR_COMMENT_BIT_SET.contains(contextType)
|| contextType == JetTokens.SEMICOLON
|| contextType == JetTokens.COMMA
|| contextType == JetTokens.RPAR
@@ -44,11 +44,11 @@ public class JetPluginUtil {
LinkedList<String> fullName = Lists.newLinkedList();
while (declarationDescriptor != null && !(declarationDescriptor instanceof ModuleDescriptor)) {
fullName.addFirst(declarationDescriptor.getName().getName());
fullName.addFirst(declarationDescriptor.getName().asString());
declarationDescriptor = declarationDescriptor.getContainingDeclaration();
}
assert fullName.size() > 0;
if (JavaDescriptorResolver.JAVA_ROOT.getName().equals(fullName.getFirst())) {
if (JavaDescriptorResolver.JAVA_ROOT.asString().equals(fullName.getFirst())) {
fullName.removeFirst();
}
return fullName;
@@ -0,0 +1,184 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.actions;
import com.intellij.codeInsight.hint.QuestionAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopupStep;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.Modality;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetClassBody;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil;
import org.jetbrains.jet.plugin.codeInsight.ReferenceToClassesShortening;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Changes method signature to one of provided signatures.
* Based on {@link JetAddImportAction}
*/
public class JetAddFunctionToClassifierAction implements QuestionAction {
private final List<FunctionDescriptor> functionsToAdd;
private final Project project;
private final Editor editor;
private final BindingContext bindingContext;
/**
* @param project Project where action takes place.
* @param editor Editor where modification should be done.
* @param bindingContext BindingContext to be used for finding type declarations.
* @param functionsToAdd List of possible functions to add.
*/
public JetAddFunctionToClassifierAction(
@NotNull Project project,
@NotNull Editor editor,
@NotNull BindingContext bindingContext,
@NotNull List<FunctionDescriptor> functionsToAdd
) {
this.project = project;
this.editor = editor;
this.bindingContext = bindingContext;
this.functionsToAdd = new ArrayList<FunctionDescriptor>(functionsToAdd);
}
private static void addFunction(
@NotNull final Project project,
@NotNull final ClassDescriptor typeDescriptor,
@NotNull final FunctionDescriptor functionDescriptor,
@NotNull BindingContext bindingContext
) {
final String signatureString = CodeInsightUtils.createFunctionSignatureStringFromDescriptor(
functionDescriptor,
/* shortTypeNames = */ false);
PsiDocumentManager.getInstance(project).commitAllDocuments();
final JetClass classifierDeclaration = (JetClass) DescriptorToDeclarationUtil.getDeclaration(project, typeDescriptor, bindingContext);
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
JetClassBody body = classifierDeclaration.getBody();
if (body == null) {
PsiElement whitespaceBefore = classifierDeclaration.add(JetPsiFactory.createWhiteSpace(project));
body = (JetClassBody) classifierDeclaration.addAfter(JetPsiFactory.createEmptyClassBody(project), whitespaceBefore);
classifierDeclaration.addAfter(JetPsiFactory.createNewLine(project), body);
}
String functionBody = "";
if (typeDescriptor.getKind() != ClassKind.TRAIT && functionDescriptor.getModality() != Modality.ABSTRACT) {
functionBody = "{}";
JetType returnType = functionDescriptor.getReturnType();
if (returnType == null || !KotlinBuiltIns.getInstance().isUnit(returnType)) {
functionBody = "{ throw UnsupportedOperationException() }";
}
}
JetNamedFunction functionElement = JetPsiFactory.createFunction(project, signatureString + functionBody);
PsiElement anchor = body.getRBrace();
JetNamedFunction insertedFunctionElement = (JetNamedFunction) body.addBefore(functionElement, anchor);
ReferenceToClassesShortening.compactReferenceToClasses(Collections.singletonList(insertedFunctionElement));
}
});
}
}, JetBundle.message("add.function.to.type.action"), null);
}
@Override
public boolean execute() {
if (functionsToAdd.isEmpty()) {
return false;
}
if (functionsToAdd.size() == 1 || !editor.getComponent().isShowing()) {
addFunction(functionsToAdd.get(0));
}
else {
chooseFunctionAndAdd();
}
return true;
}
private void chooseFunctionAndAdd() {
JBPopupFactory.getInstance().createListPopup(getFunctionPopup()).showInBestPositionFor(editor);
}
private ListPopupStep getFunctionPopup() {
return new BaseListPopupStep<FunctionDescriptor>(
JetBundle.message("add.function.to.type.action.type.chooser"), functionsToAdd) {
@Override
public boolean isAutoSelectionEnabled() {
return false;
}
@Override
public PopupStep onChosen(FunctionDescriptor selectedValue, boolean finalChoice) {
if (finalChoice) {
addFunction(selectedValue);
}
return FINAL_CHOICE;
}
@Override
public Icon getIconFor(FunctionDescriptor aValue) {
return PlatformIcons.FUNCTION_ICON;
}
@NotNull
@Override
public String getTextFor(FunctionDescriptor functionDescriptor) {
ClassDescriptor type = (ClassDescriptor) functionDescriptor.getContainingDeclaration();
return JetBundle.message("add.function.to.type.action.single",
CodeInsightUtils.createFunctionSignatureStringFromDescriptor(
functionDescriptor,
/* shortTypeNames = */ true),
type.getName().toString());
}
};
}
private void addFunction(FunctionDescriptor functionToAdd) {
addFunction(project, (ClassDescriptor) functionToAdd.getContainingDeclaration(),
functionToAdd, bindingContext);
}
}
@@ -107,7 +107,7 @@ public class JetAddImportAction implements QuestionAction {
return FINAL_CHOICE;
}
List<String> toExclude = AddImportAction.getAllExcludableStrings(selectedValue.getFqName());
List<String> toExclude = AddImportAction.getAllExcludableStrings(selectedValue.asString());
return new BaseListPopupStep<String>(null, toExclude) {
@NotNull
@@ -135,7 +135,7 @@ public class JetAddImportAction implements QuestionAction {
@NotNull
@Override
public String getTextFor(FqName value) {
return value.getFqName();
return value.asString();
}
@Override
@@ -39,7 +39,7 @@ public class JetGotoClassContributor implements GotoClassContributor {
JetNamedDeclaration jetClass = (JetNamedDeclaration) item;
FqName name = JetPsiUtil.getFQName(jetClass);
if (name != null) {
return name.getFqName();
return name.asString();
}
}
@@ -107,7 +107,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
Collection<FqName> fqNames = packageClasses.get(name);
if (!fqNames.isEmpty()) {
for (FqName fqName : fqNames) {
PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.getFqName(), scope);
PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope);
if (psiClass != null) {
result.add(psiClass);
}
@@ -123,10 +123,10 @@ public class JetShortNamesCache extends PsiShortNamesCache {
for (JetClassOrObject classOrObject : classOrObjects) {
FqName fqName = JetPsiUtil.getFQName(classOrObject);
if (fqName != null) {
assert fqName.shortName().getName().equals(name) : "A declaration obtained from index has non-matching name:\n" +
assert fqName.shortName().asString().equals(name) : "A declaration obtained from index has non-matching name:\n" +
"in index: " + name + "\n" +
"declared: " + fqName.shortName() + "(" + fqName + ")";
PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.getFqName(), scope);
PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope);
if (psiClass != null) {
result.add(psiClass);
}
@@ -230,7 +230,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
Set<FunctionDescriptor> result = Sets.newHashSet();
Collection<PsiMethod> topLevelFunctionPrototypes = JetFromJavaDescriptorHelper.getTopLevelFunctionPrototypesByName(
referenceName.getName(), project, scope);
referenceName.asString(), project, scope);
for (PsiMethod method : topLevelFunctionPrototypes) {
FqName functionFQN = JetFromJavaDescriptorHelper.getJetTopLevelDeclarationFQN(method);
if (functionFQN != null) {
@@ -246,7 +246,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
}
Set<FqName> affectedPackages = Sets.newHashSet();
Collection<JetNamedFunction> jetNamedFunctions = JetShortFunctionNameIndex.getInstance().get(referenceName.getName(), project, scope);
Collection<JetNamedFunction> jetNamedFunctions = JetShortFunctionNameIndex.getInstance().get(referenceName.asString(), project, scope);
for (JetNamedFunction jetNamedFunction : jetNamedFunctions) {
PsiFile containingFile = jetNamedFunction.getContainingFile();
if (containingFile instanceof JetFile) {
@@ -354,7 +354,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
for (String fqName : JetFullClassNameIndex.getInstance().getAllKeys(project)) {
FqName classFQName = new FqName(fqName);
if (acceptedShortNameCondition.value(classFQName.shortName().getName())) {
if (acceptedShortNameCondition.value(classFQName.shortName().asString())) {
classDescriptors.addAll(getJetClassesDescriptorsByFQName(analyzer, classFQName));
}
}
@@ -364,7 +364,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
private Collection<ClassDescriptor> getJetClassesDescriptorsByFQName(@NotNull KotlinCodeAnalyzer analyzer, @NotNull FqName classFQName) {
Collection<JetClassOrObject> jetClassOrObjects = JetFullClassNameIndex.getInstance().get(
classFQName.getFqName(), project, GlobalSearchScope.allScope(project));
classFQName.asString(), project, GlobalSearchScope.allScope(project));
if (jetClassOrObjects.isEmpty()) {
// This fqn is absent in caches, dead or not in scope
@@ -31,11 +31,9 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.KotlinLightClassForExplicitDeclaration;
import org.jetbrains.jet.asJava.LightClassConstructionContext;
import org.jetbrains.jet.asJava.LightClassGenerationSupport;
import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.plugin.libraries.JetSourceNavigationHelper;
@@ -70,13 +68,13 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
@NotNull
@Override
public Collection<JetClassOrObject> findClassOrObjectDeclarations(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope) {
return JetFullClassNameIndex.getInstance().get(fqName.getFqName(), project, kotlinSources(searchScope));
return JetFullClassNameIndex.getInstance().get(fqName.asString(), project, kotlinSources(searchScope));
}
@NotNull
@Override
public Collection<JetFile> findFilesForPackage(@NotNull final FqName fqName, @NotNull GlobalSearchScope searchScope) {
Collection<JetFile> files = JetAllPackagesIndex.getInstance().get(fqName.getFqName(), project, kotlinSources(searchScope));
Collection<JetFile> files = JetAllPackagesIndex.getInstance().get(fqName.asString(), project, kotlinSources(searchScope));
return ContainerUtil.filter(files, new Condition<JetFile>() {
@Override
public boolean value(JetFile file) {
@@ -90,20 +88,20 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
public Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage(
@NotNull FqName packageFqName, @NotNull GlobalSearchScope searchScope
) {
return JetClassByPackageIndex.getInstance().get(packageFqName.getFqName(), project, kotlinSources(searchScope));
return JetClassByPackageIndex.getInstance().get(packageFqName.asString(), project, kotlinSources(searchScope));
}
@Override
public boolean packageExists(
@NotNull FqName fqName, @NotNull GlobalSearchScope scope
) {
return !JetAllPackagesIndex.getInstance().get(fqName.getFqName(), project, kotlinSources(scope)).isEmpty();
return !JetAllPackagesIndex.getInstance().get(fqName.asString(), project, kotlinSources(scope)).isEmpty();
}
@NotNull
@Override
public Collection<FqName> getSubPackages(@NotNull FqName fqn, @NotNull GlobalSearchScope scope) {
Collection<JetFile> files = JetAllPackagesIndex.getInstance().get(fqn.getFqName(), project, kotlinSources(scope));
Collection<JetFile> files = JetAllPackagesIndex.getInstance().get(fqn.asString(), project, kotlinSources(scope));
Set<FqName> result = Sets.newHashSet();
for (JetFile file : files) {
@@ -141,7 +139,7 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
Collection<JetFile> files = findFilesForPackage(new FqName(packageFqName), scope);
if (!files.isEmpty()) {
FqName packageClassFqName = PackageClassUtils.getPackageClassFqName(new FqName(packageFqName));
result.putValue(packageClassFqName.shortName().getName(), packageClassFqName);
result.putValue(packageClassFqName.shortName().asString(), packageClassFqName);
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.jet.plugin.codeInsight;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
@@ -30,11 +31,15 @@ public final class DescriptorToDeclarationUtil {
}
public static PsiElement getDeclaration(JetFile file, DeclarationDescriptor descriptor, BindingContext bindingContext) {
return getDeclaration(file.getProject(), descriptor, bindingContext);
}
public static PsiElement getDeclaration(Project project, DeclarationDescriptor descriptor, BindingContext bindingContext) {
Collection<PsiElement> elements = BindingContextUtils.descriptorToDeclarations(bindingContext, descriptor);
if (elements.isEmpty()) {
BuiltInsReferenceResolver libraryReferenceResolver =
file.getProject().getComponent(BuiltInsReferenceResolver.class);
project.getComponent(BuiltInsReferenceResolver.class);
elements = libraryReferenceResolver.resolveStandardLibrarySymbol(descriptor);
}
@@ -51,14 +51,17 @@ public class GotoSuperActionHandler implements CodeInsightActionHandler {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
if (element == null) return;
@SuppressWarnings("unchecked") JetNamedDeclaration funOrClass =
PsiTreeUtil.getParentOfType(element, JetNamedFunction.class, JetClass.class, JetProperty.class);
if (funOrClass == null) return;
@SuppressWarnings("unchecked") JetDeclaration declaration =
PsiTreeUtil.getParentOfType(element,
JetNamedFunction.class,
JetClass.class,
JetProperty.class,
JetObjectDeclaration.class);
if (declaration == null) return;
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) file).getBindingContext();
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, funOrClass);
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration);
Collection<? extends DeclarationDescriptor> superDescriptors;
String message;
@@ -81,7 +81,7 @@ public class ReferenceToClassesShortening {
}
private void compactReferenceToClass(JetUserType userType, ClassDescriptor targetClass) {
String name = targetClass.getName().getName();
String name = targetClass.getName().asString();
DeclarationDescriptor parent = targetClass.getContainingDeclaration();
while (parent instanceof ClassDescriptor) {
name = parent.getName() + "." + name;
@@ -1,69 +0,0 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
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.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.plugin.JetBundle;
public class AssignmentWithIfExpressionToStatementIntention extends BaseIntentionAction {
public AssignmentWithIfExpressionToStatementIntention() {
setText(JetBundle.message("transform.assignment.with.if.expression.to.statement"));
}
@NotNull
@Override
public String getFamilyName() {
return JetBundle.message("transform.assignment.with.if.expression.to.statement.family");
}
@Nullable
private static JetBinaryExpression getAssignment(@NotNull Editor editor, @NotNull PsiFile file) {
int offset = editor.getCaretModel().getOffset();
PsiElement element = file.findElementAt(offset);
while (element != null) {
if (CodeTransformationUtils.checkAssignmentWithIfExpression(element)) return (JetBinaryExpression)element;
PsiElement parent = PsiTreeUtil.getParentOfType(element, JetBinaryExpression.class, false);
element = (element != parent) ? parent : null;
}
return null;
}
@Override
public boolean isAvailable(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
return getAssignment(editor, file) != null;
}
@Override
public void invoke(
@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file
) throws IncorrectOperationException {
JetBinaryExpression assignment = getAssignment(editor, file);
assert assignment != null;
CodeTransformationUtils.transformAssignmentWithIfExpressionToStatement(assignment);
}
}
@@ -1,166 +0,0 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.ArrayList;
import java.util.List;
public class CodeTransformationUtils {
private static List<JetExpression> getIfExpressionOutcomes(@NotNull JetElement root) {
return root.accept(
new JetVisitor<List<JetExpression>, List<JetExpression>>() {
@Override
public List<JetExpression> visitExpression(JetExpression expression, List<JetExpression> data) {
data.add(expression);
return data;
}
@Override
public List<JetExpression> visitBlockExpression(
JetBlockExpression expression, List<JetExpression> data) {
int n = expression.getStatements().size();
if (n > 0) {
expression.getStatements().get(n - 1).accept(this, data);
} else {
data.add(expression);
}
return data;
}
@SuppressWarnings("ConstantConditions")
@Override
public List<JetExpression> visitIfExpression(
JetIfExpression expression, List<JetExpression> data) {
if (expression.getThen() != null) {
expression.getThen().accept(this, data);
}
if (expression.getElse() != null) {
expression.getElse().accept(this, data);
}
return data;
}
},
new ArrayList<JetExpression>()
);
}
private static Boolean checkAllIfExpressionsAreComplete(@NotNull JetElement root) {
return root.accept(
new JetVisitor<Boolean, Boolean>() {
@Override
public Boolean visitJetElement(JetElement element, Boolean data) {
return data;
}
@SuppressWarnings("ConstantConditions")
@Override
public Boolean visitIfExpression(JetIfExpression expression, Boolean data) {
if (data && expression.getThen() != null) {
data = expression.getThen().accept(this, data);
} else {
data = false;
}
if (data && expression.getElse() != null) {
data = expression.getElse().accept(this, data);
} else {
data = false;
}
return data;
}
},
true
);
}
public static boolean isAssignment(@NotNull PsiElement element) {
if (!(element instanceof JetBinaryExpression)) return false;
JetBinaryExpression binaryExpression = (JetBinaryExpression)element;
if (binaryExpression.getOperationReference().getReferencedNameElementType() != JetTokens.EQ) return false;
return true;
}
private static boolean checkAllOutcomesAreCompatibleAssignments(@NotNull List<JetExpression> outcomes) {
JetExpression lastLhs = null;
for (JetExpression outcome : outcomes) {
if (!isAssignment(outcome)) return false;
JetExpression currLhs = ((JetBinaryExpression)outcome).getLeft();
if (!(currLhs instanceof JetSimpleNameExpression)) return false;
if (lastLhs == null) {
lastLhs = currLhs;
} else if (!lastLhs.getText().equals(currLhs.getText())) return false;
}
return true;
}
static boolean checkIfStatementWithAssignments(@NotNull JetIfExpression ifExpression) {
if (ifExpression.getParent() == null) return false;
List<JetExpression> outcomes = getIfExpressionOutcomes(ifExpression);
return !outcomes.isEmpty() && checkAllIfExpressionsAreComplete(ifExpression) && checkAllOutcomesAreCompatibleAssignments(outcomes);
}
static boolean checkAssignmentWithIfExpression(@NotNull PsiElement element) {
if (!isAssignment(element)) return false;
JetBinaryExpression assignment = (JetBinaryExpression)element;
return (assignment.getLeft() instanceof JetSimpleNameExpression) &&
(assignment.getRight() instanceof JetIfExpression);
}
@SuppressWarnings("ConstantConditions")
static void transformIfStatementWithAssignmentsToExpression(@NotNull JetIfExpression ifExpression) {
Project project = ifExpression.getProject();
List<JetExpression> outcomes = getIfExpressionOutcomes(ifExpression);
JetExpression lhs = ((JetBinaryExpression)outcomes.get(0)).getLeft();
JetBinaryExpression assignment = JetPsiFactory.createAssignment(project, lhs, ifExpression);
assignment = (JetBinaryExpression)ifExpression.replace(assignment);
ifExpression = (JetIfExpression)assignment.getRight();
for (JetExpression outcome : getIfExpressionOutcomes(ifExpression)) {
outcome.replace(((JetBinaryExpression)outcome).getRight());
}
}
@SuppressWarnings("ConstantConditions")
static void transformAssignmentWithIfExpressionToStatement(@NotNull JetBinaryExpression assignment) {
Project project = assignment.getProject();
String varName = assignment.getLeft().getText();
JetIfExpression ifExpression = (JetIfExpression)assignment.getRight();
ifExpression = (JetIfExpression)assignment.replace(ifExpression);
for (JetExpression outcome : getIfExpressionOutcomes(ifExpression)) {
JetBinaryExpression localAssignment = JetPsiFactory.createAssignment(project, JetPsiFactory.createExpression(project, varName), outcome);
outcome.replace(localAssignment);
}
}
private CodeTransformationUtils() {
}
}
@@ -1,64 +0,0 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
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.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetIfExpression;
import org.jetbrains.jet.plugin.JetBundle;
public class IfStatementWithAssignmentsToExpressionIntention extends BaseIntentionAction {
public IfStatementWithAssignmentsToExpressionIntention() {
setText(JetBundle.message("transform.if.statement.with.assignments.to.expression"));
}
@NotNull
@Override
public String getFamilyName() {
return JetBundle.message("transform.if.statement.with.assignments.to.expression.family");
}
@Nullable
private static JetIfExpression getOriginalExpression(@NotNull Editor editor, @NotNull PsiFile file) {
int offset = editor.getCaretModel().getOffset();
PsiElement element = file.findElementAt(offset);
return PsiTreeUtil.getParentOfType(element, JetIfExpression.class, false);
}
@Override
public boolean isAvailable(
@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
JetIfExpression ifExpression = getOriginalExpression(editor, file);
return (ifExpression != null) && CodeTransformationUtils.checkIfStatementWithAssignments(ifExpression);
}
@Override
public void invoke(
@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file
) throws IncorrectOperationException {
JetIfExpression ifExpression = getOriginalExpression(editor, file);
assert ifExpression != null;
CodeTransformationUtils.transformIfStatementWithAssignmentsToExpression(ifExpression);
}
}
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations;
import com.google.common.base.Predicate;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
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.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public abstract class AbstractCodeTransformationIntention<T extends Transformer> extends BaseIntentionAction {
private final T transformer;
private final Predicate<PsiElement> isApplicable;
protected AbstractCodeTransformationIntention(@NotNull T transformer, @NotNull Predicate<PsiElement> isApplicable) {
this.transformer = transformer;
this.isApplicable = isApplicable;
setText(JetBundle.message(transformer.getKey()));
}
@Nullable
private PsiElement getTarget(@NotNull Editor editor, @NotNull PsiFile file) {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
return JetPsiUtil.getParentByTypeAndPredicate(element, JetElement.class, isApplicable, false);
}
@NotNull
@Override
public String getFamilyName() {
return JetBundle.message(transformer.getKey() + ".family");
}
@Override
public boolean isAvailable(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
return getTarget(editor, file) != null;
}
@Override
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) throws IncorrectOperationException {
PsiElement target = getTarget(editor, file);
assert target != null : "Intention is not applicable";
transformer.transform(target, editor, (JetFile) file);
}
}
@@ -0,0 +1,331 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations;
import com.google.common.base.Predicate;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import java.util.ArrayList;
import java.util.List;
public class BranchedFoldingUtils {
private BranchedFoldingUtils() {
}
private static boolean checkEquivalence(JetExpression e1, JetExpression e2) {
return e1.getText().equals(e2.getText());
}
private static final Predicate<JetElement> CHECK_ASSIGNMENT = new Predicate<JetElement>() {
@Override
public boolean apply(@Nullable JetElement input) {
if (input == null || !JetPsiUtil.isAssignment(input)) {
return false;
}
JetBinaryExpression assignment = (JetBinaryExpression)input;
if (assignment.getRight() == null || !(assignment.getLeft() instanceof JetSimpleNameExpression)) {
return false;
}
if (assignment.getParent() instanceof JetBlockExpression) {
//noinspection ConstantConditions
return !JetPsiUtil.checkVariableDeclarationInBlock((JetBlockExpression) assignment.getParent(), assignment.getLeft().getText());
}
return true;
}
};
private static final Predicate<JetElement> CHECK_RETURN = new Predicate<JetElement>() {
@Override
public boolean apply(@Nullable JetElement input) {
return (input instanceof JetReturnExpression) && ((JetReturnExpression)input).getReturnedExpression() != null;
}
};
private static JetBinaryExpression getFoldableBranchedAssignment(JetExpression branch) {
return (JetBinaryExpression)JetPsiUtil.getOutermostLastBlockElement(branch, CHECK_ASSIGNMENT);
}
private static JetReturnExpression getFoldableBranchedReturn(JetExpression branch) {
return (JetReturnExpression)JetPsiUtil.getOutermostLastBlockElement(branch, CHECK_RETURN);
}
private static boolean checkAssignmentsMatch(JetBinaryExpression a1, JetBinaryExpression a2) {
return checkEquivalence(a1.getLeft(), a2.getLeft()) && a1.getOperationToken().equals(a2.getOperationToken());
}
private static boolean checkFoldableIfExpressionWithAssignments(JetIfExpression ifExpression) {
JetExpression thenBranch = ifExpression.getThen();
JetExpression elseBranch = ifExpression.getElse();
JetBinaryExpression thenAssignment = getFoldableBranchedAssignment(thenBranch);
JetBinaryExpression elseAssignment = getFoldableBranchedAssignment(elseBranch);
if (thenAssignment == null || elseAssignment == null) return false;
return checkAssignmentsMatch(thenAssignment, elseAssignment);
}
private static boolean checkFoldableWhenExpressionWithAssignments(JetWhenExpression whenExpression) {
if (!JetPsiUtil.checkWhenExpressionHasSingleElse(whenExpression)) return false;
List<JetWhenEntry> entries = whenExpression.getEntries();
if (entries.isEmpty()) return false;
List<JetBinaryExpression> assignments = new ArrayList<JetBinaryExpression>();
for (JetWhenEntry entry : entries) {
JetBinaryExpression assignment = getFoldableBranchedAssignment(entry.getExpression());
if (assignment == null) return false;
assignments.add(assignment);
}
assert !assignments.isEmpty();
JetBinaryExpression firstAssignment = assignments.get(0);
for (JetBinaryExpression assignment : assignments) {
if (!checkAssignmentsMatch(assignment, firstAssignment)) return false;
}
return true;
}
private static boolean checkFoldableIfExpressionWithReturns(JetIfExpression ifExpression) {
return getFoldableBranchedReturn(ifExpression.getThen()) != null &&
getFoldableBranchedReturn(ifExpression.getElse()) != null;
}
private static boolean checkFoldableWhenExpressionWithReturns(JetWhenExpression whenExpression) {
if (!JetPsiUtil.checkWhenExpressionHasSingleElse(whenExpression)) return false;
List<JetWhenEntry> entries = whenExpression.getEntries();
if (entries.isEmpty()) return false;
for (JetWhenEntry entry : entries) {
if (getFoldableBranchedReturn(entry.getExpression()) == null) return false;
}
return true;
}
private static boolean checkFoldableIfExpressionWithAsymmetricReturns(JetIfExpression ifExpression) {
if (getFoldableBranchedReturn(ifExpression.getThen()) == null ||
ifExpression.getElse() != null) {
return false;
}
PsiElement nextElement = JetPsiUtil.skipTrailingWhitespacesAndComments(ifExpression);
return (nextElement instanceof JetExpression) && getFoldableBranchedReturn((JetExpression) nextElement) != null;
}
@Nullable
public static FoldableKind getFoldableExpressionKind(@Nullable JetExpression root) {
if (root instanceof JetIfExpression) {
JetIfExpression ifExpression = (JetIfExpression)root;
if (checkFoldableIfExpressionWithAssignments(ifExpression)) return FoldableKind.IF_TO_ASSIGNMENT;
if (checkFoldableIfExpressionWithReturns(ifExpression)) return FoldableKind.IF_TO_RETURN;
if (checkFoldableIfExpressionWithAsymmetricReturns(ifExpression)) return FoldableKind.IF_TO_RETURN_ASYMMETRICALLY;
} else if (root instanceof JetWhenExpression) {
JetWhenExpression whenExpression = (JetWhenExpression)root;
if (checkFoldableWhenExpressionWithAssignments(whenExpression)) return FoldableKind.WHEN_TO_ASSIGNMENT;
if (checkFoldableWhenExpressionWithReturns(whenExpression)) return FoldableKind.WHEN_TO_RETURN;
}
return null;
}
public static final String FOLD_WITHOUT_CHECK = "Expression must be checked before folding";
private static void assertNotNull(JetExpression expression) {
assert expression != null : FOLD_WITHOUT_CHECK;
}
public static void foldIfExpressionWithAssignments(JetIfExpression ifExpression) {
Project project = ifExpression.getProject();
JetBinaryExpression thenAssignment = getFoldableBranchedAssignment(ifExpression.getThen());
assertNotNull(thenAssignment);
String op = thenAssignment.getOperationReference().getText();
JetSimpleNameExpression lhs = (JetSimpleNameExpression) thenAssignment.getLeft();
JetBinaryExpression assignment = JetPsiFactory.createBinaryExpression(project, lhs, op, ifExpression);
JetIfExpression newIfExpression = (JetIfExpression)assignment.getRight();
assertNotNull(newIfExpression);
//noinspection ConstantConditions
thenAssignment = getFoldableBranchedAssignment(newIfExpression.getThen());
JetBinaryExpression elseAssignment = getFoldableBranchedAssignment(newIfExpression.getElse());
assertNotNull(thenAssignment);
assertNotNull(elseAssignment);
JetExpression thenRhs = thenAssignment.getRight();
JetExpression elseRhs = elseAssignment.getRight();
assertNotNull(thenRhs);
assertNotNull(elseRhs);
//noinspection ConstantConditions
thenAssignment.replace(thenRhs);
//noinspection ConstantConditions
elseAssignment.replace(elseRhs);
ifExpression.replace(assignment);
}
public static void foldIfExpressionWithReturns(JetIfExpression ifExpression) {
Project project = ifExpression.getProject();
JetReturnExpression newReturnExpression = JetPsiFactory.createReturn(project, ifExpression);
JetIfExpression newIfExpression = (JetIfExpression)newReturnExpression.getReturnedExpression();
assertNotNull(newIfExpression);
//noinspection ConstantConditions
JetReturnExpression thenReturn = getFoldableBranchedReturn(newIfExpression.getThen());
JetReturnExpression elseReturn = getFoldableBranchedReturn(newIfExpression.getElse());
assertNotNull(thenReturn);
assertNotNull(elseReturn);
JetExpression thenExpr = thenReturn.getReturnedExpression();
JetExpression elseExpr = elseReturn.getReturnedExpression();
assertNotNull(thenExpr);
assertNotNull(elseExpr);
//noinspection ConstantConditions
thenReturn.replace(thenExpr);
//noinspection ConstantConditions
elseReturn.replace(elseExpr);
ifExpression.replace(newReturnExpression);
}
public static void foldIfExpressionWithAsymmetricReturns(JetIfExpression ifExpression) {
Project project = ifExpression.getProject();
JetExpression condition = ifExpression.getCondition();
JetExpression thenRoot = ifExpression.getThen();
JetExpression elseRoot = (JetExpression)JetPsiUtil.skipTrailingWhitespacesAndComments(ifExpression);
assertNotNull(condition);
assertNotNull(thenRoot);
assertNotNull(elseRoot);
//noinspection ConstantConditions
JetIfExpression newIfExpression = JetPsiFactory.createIf(project, condition, thenRoot, elseRoot);
JetReturnExpression newReturnExpression = JetPsiFactory.createReturn(project, newIfExpression);
newIfExpression = (JetIfExpression)newReturnExpression.getReturnedExpression();
assertNotNull(newIfExpression);
//noinspection ConstantConditions
JetReturnExpression thenReturn = getFoldableBranchedReturn(newIfExpression.getThen());
JetReturnExpression elseReturn = getFoldableBranchedReturn(newIfExpression.getElse());
assertNotNull(thenReturn);
assertNotNull(elseReturn);
JetExpression thenExpr = thenReturn.getReturnedExpression();
JetExpression elseExpr = elseReturn.getReturnedExpression();
assertNotNull(thenExpr);
assertNotNull(elseExpr);
//noinspection ConstantConditions
thenReturn.replace(thenExpr);
//noinspection ConstantConditions
elseReturn.replace(elseExpr);
elseRoot.delete();
ifExpression.replace(newReturnExpression);
}
@SuppressWarnings("ConstantConditions")
public static void foldWhenExpressionWithAssignments(JetWhenExpression whenExpression) {
Project project = whenExpression.getProject();
assert !whenExpression.getEntries().isEmpty() : FOLD_WITHOUT_CHECK;
JetBinaryExpression firstAssignment = getFoldableBranchedAssignment(whenExpression.getEntries().get(0).getExpression());
assertNotNull(firstAssignment);
String op = firstAssignment.getOperationReference().getText();
JetSimpleNameExpression lhs = (JetSimpleNameExpression) firstAssignment.getLeft();
JetBinaryExpression assignment = JetPsiFactory.createBinaryExpression(project, lhs, op, whenExpression);
JetWhenExpression newWhenExpression = (JetWhenExpression)assignment.getRight();
assertNotNull(newWhenExpression);
for (JetWhenEntry entry : newWhenExpression.getEntries()) {
JetBinaryExpression currAssignment = getFoldableBranchedAssignment(entry.getExpression());
assertNotNull(currAssignment);
JetExpression currRhs = currAssignment.getRight();
assertNotNull(currRhs);
currAssignment.replace(currRhs);
}
whenExpression.replace(assignment);
}
public static void foldWhenExpressionWithReturns(JetWhenExpression whenExpression) {
Project project = whenExpression.getProject();
assert !whenExpression.getEntries().isEmpty() : FOLD_WITHOUT_CHECK;
JetReturnExpression newReturnExpression = JetPsiFactory.createReturn(project, whenExpression);
JetWhenExpression newWhenExpression = (JetWhenExpression)newReturnExpression.getReturnedExpression();
assertNotNull(newWhenExpression);
//noinspection ConstantConditions
for (JetWhenEntry entry : newWhenExpression.getEntries()) {
JetReturnExpression currReturn = getFoldableBranchedReturn(entry.getExpression());
assertNotNull(currReturn);
JetExpression currExpr = currReturn.getReturnedExpression();
assertNotNull(currExpr);
//noinspection ConstantConditions
currReturn.replace(currExpr);
}
whenExpression.replace(newReturnExpression);
}
}
@@ -0,0 +1,263 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.codeInsight.ReferenceToClassesShortening;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.Collections;
public class BranchedUnfoldingUtils {
private BranchedUnfoldingUtils() {
}
private static JetExpression getOutermostLastBlockElement(@Nullable JetExpression expression) {
return (JetExpression) JetPsiUtil.getOutermostLastBlockElement(expression, JetPsiUtil.ANY_JET_ELEMENT);
}
@Nullable
public static UnfoldableKind getUnfoldableExpressionKind(@Nullable JetExpression root) {
if (root == null) return null;
if (JetPsiUtil.isAssignment(root)) {
JetBinaryExpression assignment = (JetBinaryExpression) root;
assertNotNull(assignment.getLeft());
JetExpression rhs = assignment.getRight();
if (rhs instanceof JetIfExpression) return UnfoldableKind.ASSIGNMENT_TO_IF;
if (rhs instanceof JetWhenExpression && JetPsiUtil.checkWhenExpressionHasSingleElse((JetWhenExpression) rhs)) {
return UnfoldableKind.ASSIGNMENT_TO_WHEN;
}
}
else if (root instanceof JetReturnExpression) {
JetExpression resultExpr = ((JetReturnExpression) root).getReturnedExpression();
if (resultExpr instanceof JetIfExpression) return UnfoldableKind.RETURN_TO_IF;
if (resultExpr instanceof JetWhenExpression && JetPsiUtil.checkWhenExpressionHasSingleElse((JetWhenExpression) resultExpr)) {
return UnfoldableKind.RETURN_TO_WHEN;
}
}
else if (root instanceof JetProperty) {
JetProperty property = (JetProperty) root;
if (!property.isLocal()) return null;
JetExpression initializer = property.getInitializer();
if (initializer instanceof JetIfExpression) return UnfoldableKind.PROPERTY_TO_IF;
if (initializer instanceof JetWhenExpression && JetPsiUtil.checkWhenExpressionHasSingleElse((JetWhenExpression) initializer)) {
return UnfoldableKind.PROPERTY_TO_WHEN;
}
}
return null;
}
public static final String UNFOLD_WITHOUT_CHECK = "Expression must be checked before unfolding";
private static void assertNotNull(Object value) {
assert value != null : UNFOLD_WITHOUT_CHECK;
}
public static void unfoldAssignmentToIf(@NotNull JetBinaryExpression assignment, @NotNull Editor editor) {
Project project = assignment.getProject();
String op = assignment.getOperationReference().getText();
JetExpression lhs = assignment.getLeft();
JetIfExpression ifExpression = (JetIfExpression) assignment.getRight();
assertNotNull(ifExpression);
//noinspection ConstantConditions
JetIfExpression newIfExpression = (JetIfExpression) ifExpression.copy();
JetExpression thenExpr = getOutermostLastBlockElement(newIfExpression.getThen());
JetExpression elseExpr = getOutermostLastBlockElement(newIfExpression.getElse());
assertNotNull(thenExpr);
assertNotNull(elseExpr);
//noinspection ConstantConditions
thenExpr.replace(JetPsiFactory.createBinaryExpression(project, lhs, op, thenExpr));
elseExpr.replace(JetPsiFactory.createBinaryExpression(project, lhs, op, elseExpr));
PsiElement resultElement = assignment.replace(newIfExpression);
editor.getCaretModel().moveToOffset(resultElement.getTextOffset());
}
public static void unfoldAssignmentToWhen(@NotNull JetBinaryExpression assignment, @NotNull Editor editor) {
Project project = assignment.getProject();
String op = assignment.getOperationReference().getText();
JetExpression lhs = assignment.getLeft();
JetWhenExpression whenExpression = (JetWhenExpression) assignment.getRight();
assertNotNull(whenExpression);
//noinspection ConstantConditions
JetWhenExpression newWhenExpression = (JetWhenExpression) whenExpression.copy();
for (JetWhenEntry entry : newWhenExpression.getEntries()) {
JetExpression currExpr = getOutermostLastBlockElement(entry.getExpression());
assertNotNull(currExpr);
//noinspection ConstantConditions
currExpr.replace(JetPsiFactory.createBinaryExpression(project, lhs, op, currExpr));
}
PsiElement resultElement = assignment.replace(newWhenExpression);
editor.getCaretModel().moveToOffset(resultElement.getTextOffset());
}
private static JetType getPropertyTypeIfNeeded(@NotNull JetProperty property, @NotNull JetFile file) {
if (property.getTypeRef() != null) return null;
return AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext().get(BindingContext.EXPRESSION_TYPE, property.getInitializer());
}
protected interface PropertyUnfolder<T extends JetExpression> {
void processInitializer(@NotNull T newInitializer, @NotNull JetExpression propertyRef, @NotNull Project project);
}
protected static final PropertyUnfolder<JetIfExpression> IF_EXPRESSION_PROPERTY_UNFOLDER = new PropertyUnfolder<JetIfExpression>() {
@Override
public void processInitializer(
@NotNull JetIfExpression newInitializer, @NotNull JetExpression propertyRef, @NotNull Project project
) {
JetExpression thenExpr = getOutermostLastBlockElement(newInitializer.getThen());
JetExpression elseExpr = getOutermostLastBlockElement(newInitializer.getElse());
assertNotNull(thenExpr);
assertNotNull(elseExpr);
thenExpr.replace(JetPsiFactory.createBinaryExpression(project, propertyRef, "=", thenExpr));
elseExpr.replace(JetPsiFactory.createBinaryExpression(project, propertyRef, "=", elseExpr));
}
};
protected static final PropertyUnfolder<JetWhenExpression> WHEN_EXPRESSION_PROPERTY_UNFOLDER = new PropertyUnfolder<JetWhenExpression>() {
@Override
public void processInitializer(
@NotNull JetWhenExpression newInitializer, @NotNull JetExpression propertyRef, @NotNull Project project
) {
for (JetWhenEntry entry : newInitializer.getEntries()) {
JetExpression currExpr = getOutermostLastBlockElement(entry.getExpression());
assertNotNull(currExpr);
//noinspection ConstantConditions
currExpr.replace(JetPsiFactory.createBinaryExpression(project, propertyRef, "=", currExpr));
}
}
};
private static <T extends JetExpression> void unfoldProperty(
@NotNull JetProperty property, @NotNull JetFile file, PropertyUnfolder<T> unfolder
) {
Project project = property.getProject();
PsiElement parent = property.getParent();
assertNotNull(parent);
//noinspection unchecked
T initializer = (T) property.getInitializer();
assertNotNull(initializer);
JetSimpleNameExpression propertyName = JetPsiFactory.createSimpleName(project, property.getName());
//noinspection ConstantConditions, unchecked
T newInitializer = (T) initializer.copy();
unfolder.processInitializer(newInitializer, propertyName, project);
parent.addAfter(newInitializer, property);
parent.addAfter(JetPsiFactory.createNewLine(project), property);
//noinspection ConstantConditions
JetType inferredType = getPropertyTypeIfNeeded(property, file);
String typeStr = inferredType != null
? DescriptorRenderer.TEXT.renderType(inferredType)
: JetPsiUtil.getNullableText(property.getTypeRef());
property = (JetProperty) property.replace(
JetPsiFactory.createProperty(project, property.getName(), typeStr, property.isVar())
);
if (inferredType != null) {
ReferenceToClassesShortening.compactReferenceToClasses(Collections.singletonList(property.getTypeRef()));
}
}
public static void unfoldPropertyToIf(@NotNull JetProperty property, @NotNull JetFile file) {
unfoldProperty(property, file, IF_EXPRESSION_PROPERTY_UNFOLDER);
}
public static void unfoldPropertyToWhen(@NotNull JetProperty property, @NotNull JetFile file) {
unfoldProperty(property, file, WHEN_EXPRESSION_PROPERTY_UNFOLDER);
}
public static void unfoldReturnToIf(@NotNull JetReturnExpression returnExpression) {
Project project = returnExpression.getProject();
JetIfExpression ifExpression = (JetIfExpression) returnExpression.getReturnedExpression();
assertNotNull(ifExpression);
//noinspection ConstantConditions
JetIfExpression newIfExpression = (JetIfExpression) ifExpression.copy();
JetExpression thenExpr = getOutermostLastBlockElement(newIfExpression.getThen());
JetExpression elseExpr = getOutermostLastBlockElement(newIfExpression.getElse());
assertNotNull(thenExpr);
assertNotNull(elseExpr);
thenExpr.replace(JetPsiFactory.createReturn(project, thenExpr));
elseExpr.replace(JetPsiFactory.createReturn(project, elseExpr));
returnExpression.replace(newIfExpression);
}
public static void unfoldReturnToWhen(@NotNull JetReturnExpression returnExpression) {
Project project = returnExpression.getProject();
JetWhenExpression whenExpression = (JetWhenExpression) returnExpression.getReturnedExpression();
assertNotNull(whenExpression);
//noinspection ConstantConditions
JetWhenExpression newWhenExpression = (JetWhenExpression) whenExpression.copy();
for (JetWhenEntry entry : newWhenExpression.getEntries()) {
JetExpression currExpr = getOutermostLastBlockElement(entry.getExpression());
assertNotNull(currExpr);
currExpr.replace(JetPsiFactory.createReturn(project, currExpr));
}
returnExpression.replace(newWhenExpression);
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance TO 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,
* TOOUT 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetIfExpression;
import org.jetbrains.jet.lang.psi.JetWhenExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public enum FoldableKind implements Transformer {
IF_TO_ASSIGNMENT("fold.if.to.assignment") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
BranchedFoldingUtils.foldIfExpressionWithAssignments((JetIfExpression) element);
}
},
IF_TO_RETURN("fold.if.to.return") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
BranchedFoldingUtils.foldIfExpressionWithReturns((JetIfExpression) element);
}
},
IF_TO_RETURN_ASYMMETRICALLY("fold.if.to.return") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
BranchedFoldingUtils.foldIfExpressionWithAsymmetricReturns((JetIfExpression) element);
}
},
WHEN_TO_ASSIGNMENT("fold.when.to.assignment") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
BranchedFoldingUtils.foldWhenExpressionWithAssignments((JetWhenExpression) element);
}
},
WHEN_TO_RETURN("fold.when.to.return") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
BranchedFoldingUtils.foldWhenExpressionWithReturns((JetWhenExpression) element);
}
};
private final String key;
private FoldableKind(String key) {
this.key = key;
}
@NotNull
@Override
public String getKey() {
return key;
}
}
@@ -0,0 +1,163 @@
package org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.lang.psi.JetPsiUnparsingUtils.*;
public class IfWhenUtils {
public static final String TRANSFORM_WITHOUT_CHECK =
"Expression must be checked before applying transformation";
private IfWhenUtils() {
}
public static boolean checkIfToWhen(@NotNull JetIfExpression ifExpression) {
return ifExpression.getThen() != null && ifExpression.getElse() != null;
}
public static boolean checkWhenToIf(@NotNull JetWhenExpression whenExpression) {
return !whenExpression.getEntries().isEmpty() && JetPsiUtil.checkWhenExpressionHasSingleElse(whenExpression);
}
private static void assertNotNull(JetExpression expression) {
assert expression != null : TRANSFORM_WITHOUT_CHECK;
}
private static List<JetExpression> splitExpressionToOrBranches(@Nullable JetExpression expression) {
if (expression == null) return Collections.emptyList();
final List<JetExpression> branches = new ArrayList<JetExpression>();
expression.accept(
new JetVisitorVoid() {
@Override
public void visitBinaryExpression(JetBinaryExpression expression) {
if (expression.getOperationToken() == JetTokens.OROR) {
JetExpression left = expression.getLeft();
JetExpression right = expression.getRight();
if (left != null) {
left.accept(this);
}
if (right != null) {
right.accept(this);
}
} else {
visitExpression(expression);
}
}
@Override
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
JetExpression baseExpression = expression.getExpression();
if (baseExpression != null) {
baseExpression.accept(this);
}
}
@Override
public void visitExpression(JetExpression expression) {
branches.add(expression);
}
}
);
return branches;
}
public static void transformIfToWhen(@NotNull JetIfExpression ifExpression) {
JetPsiFactory.WhenBuilder builder = new JetPsiFactory.WhenBuilder();
JetIfExpression currIfExpression = ifExpression;
do {
JetExpression condition = currIfExpression.getCondition();
JetExpression thenBranch = currIfExpression.getThen();
JetExpression elseBranch = currIfExpression.getElse();
assertNotNull(thenBranch);
assertNotNull(elseBranch);
List<JetExpression> orBranches = splitExpressionToOrBranches(condition);
if (orBranches.isEmpty()) {
builder.condition("");
} else {
for (JetExpression orBranch : orBranches) {
builder.condition(orBranch);
}
}
//noinspection ConstantConditions
builder.branchExpression(thenBranch);
if (elseBranch instanceof JetIfExpression) {
currIfExpression = (JetIfExpression) elseBranch;
}
else {
currIfExpression = null;
//noinspection ConstantConditions
builder.elseEntry(elseBranch);
}
} while (currIfExpression != null);
JetWhenExpression whenExpression = builder.toExpression(ifExpression.getProject());
if (WhenUtils.checkIntroduceWhenSubject(whenExpression)) {
whenExpression = WhenUtils.introduceWhenSubject(whenExpression);
}
ifExpression.replace(whenExpression);
}
private static String combineWhenConditions(JetWhenCondition[] conditions, JetExpression subject) {
int n = conditions.length;
if (n == 0) return "";
JetWhenCondition condition = conditions[0];
assert condition != null : TRANSFORM_WITHOUT_CHECK;
StringBuilder sb = new StringBuilder();
String text = WhenUtils.whenConditionToExpressionText(condition, subject);
if (n > 1) {
text = parenthesizeTextIfNeeded(text);
}
sb.append(text);
for (int i = 1; i < n; i++) {
JetWhenCondition currCondition = conditions[i];
assert currCondition != null : TRANSFORM_WITHOUT_CHECK;
sb.append(" || ").append(parenthesizeTextIfNeeded(WhenUtils.whenConditionToExpressionText(currCondition, subject)));
}
return sb.toString();
}
public static void transformWhenToIf(@NotNull JetWhenExpression whenExpression) {
JetPsiFactory.IfChainBuilder builder = new JetPsiFactory.IfChainBuilder();
List<JetWhenEntry> entries = whenExpression.getEntries();
for (JetWhenEntry entry : entries) {
JetExpression branch = entry.getExpression();
if (entry.isElse()) {
builder.elseBranch(branch);
} else {
String branchConditionText = combineWhenConditions(entry.getConditions(), whenExpression.getSubjectExpression());
builder.ifBranch(branchConditionText, JetPsiUtil.getText(branch));
}
}
whenExpression.replace(builder.toExpression(whenExpression.getProject()));
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.psi.JetReturnExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public enum UnfoldableKind implements Transformer {
ASSIGNMENT_TO_IF("unfold.assignment.to.if") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, JetFile file) {
BranchedUnfoldingUtils.unfoldAssignmentToIf((JetBinaryExpression) element, editor);
}
},
PROPERTY_TO_IF("unfold.property.to.if") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, JetFile file) {
BranchedUnfoldingUtils.unfoldPropertyToIf((JetProperty) element, file);
}
},
RETURN_TO_IF("unfold.return.to.if") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, JetFile file) {
BranchedUnfoldingUtils.unfoldReturnToIf((JetReturnExpression) element);
}
},
ASSIGNMENT_TO_WHEN("unfold.assignment.to.when") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, JetFile file) {
BranchedUnfoldingUtils.unfoldAssignmentToWhen((JetBinaryExpression) element, editor);
}
},
PROPERTY_TO_WHEN("unfold.property.to.when") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, JetFile file) {
BranchedUnfoldingUtils.unfoldPropertyToWhen((JetProperty) element, file);
}
},
RETURN_TO_WHEN("unfold.return.to.when") {
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, JetFile file) {
BranchedUnfoldingUtils.unfoldReturnToWhen((JetReturnExpression) element);
}
};
private final String key;
private UnfoldableKind(String key) {
this.key = key;
}
@NotNull
@Override
public String getKey() {
return key;
}
}
@@ -0,0 +1,223 @@
package org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.util.JetPsiMatcher;
import static org.jetbrains.jet.lang.psi.JetPsiUnparsingUtils.*;
import java.util.List;
public class WhenUtils {
private WhenUtils() {
}
public static final String TRANSFORM_WITHOUT_CHECK =
"Expression must be checked before applying transformation";
private static void assertNotNull(Object expression) {
assert expression != null : TRANSFORM_WITHOUT_CHECK;
}
private static JetExpression getWhenConditionSubjectCandidate(JetExpression condition) {
if (condition instanceof JetIsExpression) {
return ((JetIsExpression) condition).getLeftHandSide();
}
if (condition instanceof JetBinaryExpression) {
JetBinaryExpression binaryExpression = (JetBinaryExpression) condition;
IElementType op = binaryExpression.getOperationToken();
if (op == JetTokens.EQEQ || op == JetTokens.IN_KEYWORD || op == JetTokens.NOT_IN) {
return ((JetBinaryExpression) condition).getLeft();
}
}
return null;
}
private static JetExpression getWhenSubjectCandidate(@NotNull JetWhenExpression whenExpression) {
if (whenExpression.getSubjectExpression() != null) return null;
JetExpression lastCandidate = null;
for (JetWhenEntry entry : whenExpression.getEntries()) {
JetWhenCondition[] conditions = entry.getConditions();
if (!entry.isElse() && conditions.length == 0) return null;
for (JetWhenCondition condition : conditions) {
if (!(condition instanceof JetWhenConditionWithExpression)) return null;
JetExpression currCandidate = getWhenConditionSubjectCandidate(((JetWhenConditionWithExpression) condition).getExpression());
if (!(currCandidate instanceof JetSimpleNameExpression)) return null;
if (lastCandidate == null) {
lastCandidate = currCandidate;
}
else if (!JetPsiMatcher.checkElementMatch(lastCandidate, currCandidate)) return null;
}
}
return lastCandidate;
}
public static boolean checkFlattenWhen(@NotNull JetWhenExpression whenExpression) {
JetExpression subject = whenExpression.getSubjectExpression();
if (subject != null && !(subject instanceof JetSimpleNameExpression)) return false;
if (!JetPsiUtil.checkWhenExpressionHasSingleElse(whenExpression)) return false;
JetExpression elseBranch = whenExpression.getElseExpression();
if (!(elseBranch instanceof JetWhenExpression)) return false;
JetWhenExpression nestedWhenExpression = (JetWhenExpression) elseBranch;
return JetPsiUtil.checkWhenExpressionHasSingleElse(nestedWhenExpression) &&
JetPsiMatcher.checkElementMatch(subject, nestedWhenExpression.getSubjectExpression());
}
public static boolean checkIntroduceWhenSubject(@NotNull JetWhenExpression whenExpression) {
return getWhenSubjectCandidate(whenExpression) != null;
}
public static boolean checkEliminateWhenSubject(@NotNull JetWhenExpression whenExpression) {
return whenExpression.getSubjectExpression() instanceof JetSimpleNameExpression;
}
@NotNull
public static JetWhenExpression flattenWhen(@NotNull JetWhenExpression whenExpression) {
JetExpression subjectExpression = whenExpression.getSubjectExpression();
JetExpression elseBranch = whenExpression.getElseExpression();
assert elseBranch instanceof JetWhenExpression : TRANSFORM_WITHOUT_CHECK;
JetWhenExpression nestedWhenExpression = (JetWhenExpression) elseBranch;
List<JetWhenEntry> outerEntries = whenExpression.getEntries();
List<JetWhenEntry> innerEntries = nestedWhenExpression.getEntries();
JetPsiFactory.WhenBuilder builder = new JetPsiFactory.WhenBuilder(subjectExpression);
for (JetWhenEntry entry : outerEntries) {
if (entry.isElse()) continue;
builder.entry(entry);
}
for (JetWhenEntry entry : innerEntries) {
builder.entry(entry);
}
JetWhenExpression newWhenExpression = builder.toExpression(whenExpression.getProject());
whenExpression.replace(newWhenExpression);
return newWhenExpression;
}
@NotNull
public static JetWhenExpression introduceWhenSubject(@NotNull JetWhenExpression whenExpression) {
JetExpression subject = getWhenSubjectCandidate(whenExpression);
assertNotNull(subject);
JetPsiFactory.WhenBuilder builder = new JetPsiFactory.WhenBuilder(subject);
for (JetWhenEntry entry : whenExpression.getEntries()) {
JetExpression branchExpression = entry.getExpression();
if (entry.isElse()) {
builder.elseEntry(branchExpression);
continue;
}
for (JetWhenCondition condition : entry.getConditions()) {
assert condition instanceof JetWhenConditionWithExpression : TRANSFORM_WITHOUT_CHECK;
JetExpression conditionExpression = ((JetWhenConditionWithExpression) condition).getExpression();
if (conditionExpression instanceof JetIsExpression) {
JetIsExpression isExpression = (JetIsExpression) conditionExpression;
builder.pattern(isExpression.getTypeRef(), isExpression.isNegated());
}
else if (conditionExpression instanceof JetBinaryExpression) {
JetBinaryExpression binaryExpression = (JetBinaryExpression) conditionExpression;
JetExpression rhs = binaryExpression.getRight();
IElementType op = binaryExpression.getOperationToken();
if (op == JetTokens.IN_KEYWORD) {
builder.range(rhs, false);
}
else if (op == JetTokens.NOT_IN) {
builder.range(rhs, true);
}
else if (op == JetTokens.EQEQ) {
builder.condition(rhs);
}
else assert false : TRANSFORM_WITHOUT_CHECK;
}
else assert false : TRANSFORM_WITHOUT_CHECK;
}
builder.branchExpression(branchExpression);
}
JetWhenExpression newWhenExpression = builder.toExpression(whenExpression.getProject());
whenExpression.replace(newWhenExpression);
return newWhenExpression;
}
@NotNull
static String whenConditionToExpressionText(@NotNull JetWhenCondition condition, JetExpression subject) {
if (condition instanceof JetWhenConditionIsPattern) {
JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition;
return toBinaryExpression(subject, (patternCondition.isNegated() ? "!is" : "is"), patternCondition.getTypeRef());
}
if (condition instanceof JetWhenConditionInRange) {
JetWhenConditionInRange rangeCondition = (JetWhenConditionInRange) condition;
return toBinaryExpression(subject, rangeCondition.getOperationReference().getText(), rangeCondition.getRangeExpression());
}
assert condition instanceof JetWhenConditionWithExpression : TRANSFORM_WITHOUT_CHECK;
JetExpression conditionExpression = ((JetWhenConditionWithExpression) condition).getExpression();
if (subject != null) {
return toBinaryExpression(parenthesizeIfNeeded(subject), "==", parenthesizeIfNeeded(conditionExpression));
}
return JetPsiUtil.getText(conditionExpression);
}
@NotNull
public static JetWhenExpression eliminateWhenSubject(@NotNull JetWhenExpression whenExpression) {
JetExpression subject = whenExpression.getSubjectExpression();
assertNotNull(subject);
JetPsiFactory.WhenBuilder builder = new JetPsiFactory.WhenBuilder();
for (JetWhenEntry entry : whenExpression.getEntries()) {
JetExpression branchExpression = entry.getExpression();
if (entry.isElse()) {
builder.elseEntry(branchExpression);
continue;
}
for (JetWhenCondition condition : entry.getConditions()) {
builder.condition(whenConditionToExpressionText(condition, subject));
}
builder.branchExpression(branchExpression);
}
JetWhenExpression newWhenExpression = builder.toExpression(whenExpression.getProject());
whenExpression.replace(newWhenExpression);
return newWhenExpression;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
public interface Transformer {
@NotNull
String getKey();
void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file);
}
@@ -0,0 +1,38 @@
package org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetWhenExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.AbstractCodeTransformationIntention;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.WhenUtils;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public class EliminateWhenSubjectIntention extends AbstractCodeTransformationIntention<Transformer> {
private static final Transformer TRANSFORMER = new Transformer() {
@NotNull
@Override
public String getKey() {
return "eliminate.when.subject";
}
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
WhenUtils.eliminateWhenSubject((JetWhenExpression) element);
}
};
private static final Predicate<PsiElement> IS_APPLICABLE = new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return input instanceof JetWhenExpression && WhenUtils.checkEliminateWhenSubject((JetWhenExpression) input);
}
};
public EliminateWhenSubjectIntention() {
super(TRANSFORMER, IS_APPLICABLE);
}
}
@@ -0,0 +1,38 @@
package org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetWhenExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.AbstractCodeTransformationIntention;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.WhenUtils;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public class FlattenWhenIntention extends AbstractCodeTransformationIntention<Transformer> {
private static final Transformer TRANSFORMER = new Transformer() {
@NotNull
@Override
public String getKey() {
return "flatten.when";
}
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
WhenUtils.flattenWhen((JetWhenExpression) element);
}
};
private static final Predicate<PsiElement> IS_APPLICABLE = new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return input instanceof JetWhenExpression && WhenUtils.checkFlattenWhen((JetWhenExpression) input);
}
};
public FlattenWhenIntention() {
super(TRANSFORMER, IS_APPLICABLE);
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.AbstractCodeTransformationIntention;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.BranchedFoldingUtils;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.FoldableKind;
public abstract class FoldBranchedExpressionIntention extends AbstractCodeTransformationIntention<FoldableKind> {
protected FoldBranchedExpressionIntention(@NotNull final FoldableKind foldableKind) {
super(
foldableKind,
new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return (input instanceof JetExpression) && BranchedFoldingUtils.getFoldableExpressionKind((JetExpression) input) == foldableKind;
}
}
);
}
public static class FoldIfToAssignmentIntention extends FoldBranchedExpressionIntention {
public FoldIfToAssignmentIntention() {
super(FoldableKind.IF_TO_ASSIGNMENT);
}
}
public static class FoldIfToReturnAsymmetricallyIntention extends FoldBranchedExpressionIntention {
public FoldIfToReturnAsymmetricallyIntention() {
super(FoldableKind.IF_TO_RETURN_ASYMMETRICALLY);
}
}
public static class FoldIfToReturnIntention extends FoldBranchedExpressionIntention {
public FoldIfToReturnIntention() {
super(FoldableKind.IF_TO_RETURN);
}
}
public static class FoldWhenToAssignmentIntention extends FoldBranchedExpressionIntention {
public FoldWhenToAssignmentIntention() {
super(FoldableKind.WHEN_TO_ASSIGNMENT);
}
}
public static class FoldWhenToReturnIntention extends FoldBranchedExpressionIntention {
public FoldWhenToReturnIntention() {
super(FoldableKind.WHEN_TO_RETURN);
}
}
}
@@ -0,0 +1,38 @@
package org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetIfExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.AbstractCodeTransformationIntention;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.IfWhenUtils;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public class IfToWhenIntention extends AbstractCodeTransformationIntention<Transformer> {
private static final Transformer TRANSFORMER = new Transformer() {
@NotNull
@Override
public String getKey() {
return "if.to.when";
}
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
IfWhenUtils.transformIfToWhen((JetIfExpression) element);
}
};
private static final Predicate<PsiElement> IS_APPLICABLE = new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return (input instanceof JetIfExpression) && IfWhenUtils.checkIfToWhen((JetIfExpression) input);
}
};
public IfToWhenIntention() {
super(TRANSFORMER, IS_APPLICABLE);
}
}
@@ -0,0 +1,38 @@
package org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetWhenExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.AbstractCodeTransformationIntention;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.WhenUtils;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public class IntroduceWhenSubjectIntention extends AbstractCodeTransformationIntention<Transformer> {
private static final Transformer TRANSFORMER = new Transformer() {
@NotNull
@Override
public String getKey() {
return "introduce.when.subject";
}
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
WhenUtils.introduceWhenSubject((JetWhenExpression) element);
}
};
private static final Predicate<PsiElement> IS_APPLICABLE = new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return input instanceof JetWhenExpression && WhenUtils.checkIntroduceWhenSubject((JetWhenExpression) input);
}
};
public IntroduceWhenSubjectIntention() {
super(TRANSFORMER, IS_APPLICABLE);
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.*;
public abstract class UnfoldBranchedExpressionIntention extends AbstractCodeTransformationIntention<UnfoldableKind> {
protected UnfoldBranchedExpressionIntention(@NotNull final UnfoldableKind unfoldableKind) {
super(
unfoldableKind,
new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return (input instanceof JetExpression) && BranchedUnfoldingUtils.getUnfoldableExpressionKind((JetExpression) input) == unfoldableKind;
}
}
);
}
public static class UnfoldAssignmentToIfIntention extends UnfoldBranchedExpressionIntention {
public UnfoldAssignmentToIfIntention() {
super(UnfoldableKind.ASSIGNMENT_TO_IF);
}
}
public static class UnfoldPropertyToIfIntention extends UnfoldBranchedExpressionIntention {
public UnfoldPropertyToIfIntention() {
super(UnfoldableKind.PROPERTY_TO_IF);
}
}
public static class UnfoldAssignmentToWhenIntention extends UnfoldBranchedExpressionIntention {
public UnfoldAssignmentToWhenIntention() {
super(UnfoldableKind.ASSIGNMENT_TO_WHEN);
}
}
public static class UnfoldPropertyToWhenIntention extends UnfoldBranchedExpressionIntention {
public UnfoldPropertyToWhenIntention() {
super(UnfoldableKind.PROPERTY_TO_WHEN);
}
}
public static class UnfoldReturnToIfIntention extends UnfoldBranchedExpressionIntention {
public UnfoldReturnToIfIntention() {
super(UnfoldableKind.RETURN_TO_IF);
}
}
public static class UnfoldReturnToWhenIntention extends UnfoldBranchedExpressionIntention {
public UnfoldReturnToWhenIntention() {
super(UnfoldableKind.RETURN_TO_WHEN);
}
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetWhenExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.AbstractCodeTransformationIntention;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.IfWhenUtils;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public class WhenToIfIntention extends AbstractCodeTransformationIntention<Transformer> {
private static final Transformer TRANSFORMER = new Transformer() {
@NotNull
@Override
public String getKey() {
return "when.to.if";
}
@Override
public void transform(@NotNull PsiElement element, @NotNull Editor editor, @NotNull JetFile file) {
IfWhenUtils.transformWhenToIf((JetWhenExpression) element);
}
};
private static final Predicate<PsiElement> IS_APPLICABLE = new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return (input instanceof JetWhenExpression) && IfWhenUtils.checkWhenToIf((JetWhenExpression) input);
}
};
public WhenToIfIntention() {
super(TRANSFORMER, IS_APPLICABLE);
}
}
@@ -30,7 +30,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationResolver;
class KotlinSignatureUtil {
static final String KOTLIN_SIGNATURE_ANNOTATION = JvmStdlibNames.KOTLIN_SIGNATURE.getFqName().getFqName();
static final String KOTLIN_SIGNATURE_ANNOTATION = JvmStdlibNames.KOTLIN_SIGNATURE.getFqName().asString();
private KotlinSignatureUtil() {
}
@@ -0,0 +1,76 @@
package org.jetbrains.jet.plugin.codeInsight.upDownMover;
import com.intellij.codeInsight.editorActions.moveUpDown.LineMover;
import com.intellij.codeInsight.editorActions.moveUpDown.LineRange;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
public abstract class AbstractJetUpDownMover extends LineMover {
protected AbstractJetUpDownMover() {
}
protected abstract boolean checkSourceElement(@NotNull PsiElement element);
protected abstract LineRange getElementSourceLineRange(@NotNull PsiElement element, @NotNull Editor editor, @NotNull LineRange oldRange);
@Nullable
protected LineRange getSourceRange(@NotNull PsiElement firstElement, @NotNull PsiElement lastElement, @NotNull Editor editor, LineRange oldRange) {
if (firstElement == lastElement) {
LineRange sourceRange = getElementSourceLineRange(firstElement, editor, oldRange);
if (sourceRange != null) {
sourceRange.firstElement = sourceRange.lastElement = firstElement;
}
return sourceRange;
}
PsiElement parent = PsiTreeUtil.findCommonParent(firstElement, lastElement);
if (parent == null) return null;
Pair<PsiElement, PsiElement> combinedRange = getElementRange(parent, firstElement, lastElement);
if (combinedRange == null
|| !checkSourceElement(combinedRange.first)
|| !checkSourceElement(combinedRange.second)) {
return null;
}
LineRange lineRange1 = getElementSourceLineRange(combinedRange.first, editor, oldRange);
if (lineRange1 == null) return null;
LineRange lineRange2 = getElementSourceLineRange(combinedRange.second, editor, oldRange);
if (lineRange2 == null) return null;
LineRange sourceRange = new LineRange(lineRange1.startLine, lineRange2.endLine);
sourceRange.firstElement = combinedRange.first;
sourceRange.lastElement = combinedRange.second;
return sourceRange;
}
@Nullable
protected static PsiElement getSiblingOfType(@NotNull PsiElement element, boolean down, @NotNull Class<? extends PsiElement> type) {
return down ? PsiTreeUtil.getNextSiblingOfType(element, type) : PsiTreeUtil.getPrevSiblingOfType(element, type);
}
@Nullable
protected static PsiElement firstNonWhiteSibling(@NotNull LineRange lineRange, boolean down) {
return firstNonWhiteElement(down ? lineRange.lastElement.getNextSibling() : lineRange.firstElement.getPrevSibling(), down);
}
@Nullable
protected static PsiElement firstNonWhiteSibling(@NotNull PsiElement element, boolean down) {
return firstNonWhiteElement(down ? element.getNextSibling() : element.getPrevSibling(), down);
}
@Override
public boolean checkAvailable(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
return (file instanceof JetFile) && super.checkAvailable(editor, file, info, down);
}
}
@@ -0,0 +1,225 @@
package org.jetbrains.jet.plugin.codeInsight.upDownMover;
import com.intellij.codeInsight.editorActions.moveUpDown.LineRange;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.ArrayList;
import java.util.List;
public class JetDeclarationMover extends AbstractJetUpDownMover {
public JetDeclarationMover() {
}
@NotNull
private static List<PsiElement> getDeclarationAnchors(@NotNull JetDeclaration declaration) {
final List<PsiElement> memberSuspects = new ArrayList<PsiElement>();
JetModifierList modifierList = declaration.getModifierList();
if (modifierList != null) memberSuspects.add(modifierList);
if (declaration instanceof JetNamedDeclaration) {
PsiElement nameIdentifier = ((JetNamedDeclaration) declaration).getNameIdentifier();
if (nameIdentifier != null) memberSuspects.add(nameIdentifier);
}
declaration.accept(
new JetVisitorVoid() {
@Override
public void visitAnonymousInitializer(JetClassInitializer initializer) {
PsiElement brace = initializer.getOpenBraceNode();
if (brace != null) {
memberSuspects.add(brace);
}
}
@Override
public void visitClassObject(JetClassObject classObject) {
PsiElement classKeyword = classObject.getClassKeywordNode();
if (classKeyword != null) memberSuspects.add(classKeyword);
}
@Override
public void visitNamedFunction(JetNamedFunction function) {
PsiElement equalsToken = function.getEqualsToken();
if (equalsToken != null) memberSuspects.add(equalsToken);
JetTypeParameterList typeParameterList = function.getTypeParameterList();
if (typeParameterList != null) memberSuspects.add(typeParameterList);
JetTypeReference receiverTypeRef = function.getReceiverTypeRef();
if (receiverTypeRef != null) memberSuspects.add(receiverTypeRef);
JetTypeReference returnTypeRef = function.getReturnTypeRef();
if (returnTypeRef != null) memberSuspects.add(returnTypeRef);
}
@Override
public void visitProperty(JetProperty property) {
PsiElement valOrVarNode = property.getValOrVarNode().getPsi();
if (valOrVarNode != null) memberSuspects.add(valOrVarNode);
JetTypeParameterList typeParameterList = property.getTypeParameterList();
if (typeParameterList != null) memberSuspects.add(typeParameterList);
JetTypeReference receiverTypeRef = property.getReceiverTypeRef();
if (receiverTypeRef != null) memberSuspects.add(receiverTypeRef);
JetTypeReference returnTypeRef = property.getTypeRef();
if (returnTypeRef != null) memberSuspects.add(returnTypeRef);
}
}
);
return memberSuspects;
}
private static final Class[] DECLARATION_CONTAINER_CLASSES =
{JetClassBody.class, JetClassInitializer.class, JetFunction.class, JetPropertyAccessor.class, JetFile.class};
private static final Class[] CLASSBODYLIKE_DECLARATION_CONTAINER_CLASSES = {JetClassBody.class, JetFile.class};
@Nullable
private static JetDeclaration getMovableDeclaration(@Nullable PsiElement element) {
if (element == null) return null;
JetDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetDeclaration.class, false);
if (declaration instanceof JetTypeParameter) {
return getMovableDeclaration(declaration.getParent());
}
return PsiTreeUtil.instanceOf(PsiTreeUtil.getParentOfType(declaration,
DECLARATION_CONTAINER_CLASSES),
CLASSBODYLIKE_DECLARATION_CONTAINER_CLASSES) ? declaration : null;
}
@Override
protected boolean checkSourceElement(@NotNull PsiElement element) {
return element instanceof JetDeclaration;
}
@Override
protected LineRange getElementSourceLineRange(@NotNull PsiElement element, @NotNull Editor editor, @NotNull LineRange oldRange) {
JetDeclaration declaration = (JetDeclaration) element;
Document doc = editor.getDocument();
TextRange textRange = declaration.getTextRange();
if (doc.getTextLength() < textRange.getEndOffset()) return null;
int startLine = editor.offsetToLogicalPosition(textRange.getStartOffset()).line;
int endLine = editor.offsetToLogicalPosition(textRange.getEndOffset()).line + 1;
if (startLine == oldRange.startLine || startLine == oldRange.endLine
|| endLine == oldRange.startLine || endLine == oldRange.endLine) {
return new LineRange(startLine, endLine);
}
TextRange lineTextRange = new TextRange(doc.getLineStartOffset(oldRange.startLine),
doc.getLineEndOffset(oldRange.endLine));
for (PsiElement anchor : getDeclarationAnchors(declaration)) {
TextRange suspectTextRange = anchor.getTextRange();
if (suspectTextRange != null && lineTextRange.intersects(suspectTextRange)) return new LineRange(startLine, endLine);
}
return null;
}
@Nullable
private static LineRange getTargetRange(
@NotNull Editor editor,
@NotNull PsiElement sibling,
boolean down,
@NotNull PsiElement target
) {
PsiElement start = sibling;
PsiElement end = sibling;
PsiElement nextParent = null;
// moving out of code block
if (sibling.getNode().getElementType() == (down ? JetTokens.RBRACE : JetTokens.LBRACE)) {
// elements which aren't immediately placed in class body can't leave the block
PsiElement parent = sibling.getParent();
if (!(parent instanceof JetClassBody)) return null;
JetClassOrObject jetClassOrObject = (JetClassOrObject) parent.getParent();
assert jetClassOrObject != null;
nextParent = jetClassOrObject.getParent();
if (!down) {
start = jetClassOrObject;
}
}
// moving into code block
// element may move only into class body
else if (sibling instanceof JetClassOrObject) {
JetClassOrObject jetClassOrObject = (JetClassOrObject) sibling;
JetClassBody classBody = jetClassOrObject.getBody();
// confined elements can't leave their block
if (classBody != null) {
nextParent = classBody;
start = down ? jetClassOrObject : classBody.getRBrace();
end = down ? classBody.getLBrace() : classBody.getRBrace();
}
}
if (nextParent != null) {
if (target instanceof JetClassInitializer && !(nextParent instanceof JetClassBody)) return null;
if (target instanceof JetEnumEntry) {
if (!(nextParent instanceof JetClassBody)) return null;
JetClassOrObject nextClassOrObject = (JetClassOrObject) nextParent.getParent();
assert nextClassOrObject != null;
if (!nextClassOrObject.hasModifier(JetTokens.ENUM_KEYWORD)) return null;
}
}
if (target instanceof JetPropertyAccessor && !(sibling instanceof JetPropertyAccessor)) return null;
return start != null && end != null ? new LineRange(start, end, editor.getDocument()) : null;
}
@Override
public boolean checkAvailable(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
if (!super.checkAvailable(editor, file, info, down)) return false;
LineRange oldRange = info.toMove;
Pair<PsiElement, PsiElement> psiRange = getElementRange(editor, file, oldRange);
if (psiRange == null) return false;
JetDeclaration firstDecl = getMovableDeclaration(psiRange.getFirst());
if (firstDecl == null) return false;
JetDeclaration lastDecl = getMovableDeclaration(psiRange.getSecond());
if (lastDecl == null) return false;
//noinspection ConstantConditions
LineRange sourceRange = getSourceRange(firstDecl, lastDecl, editor, oldRange);
if (sourceRange == null) return false;
PsiElement sibling = firstNonWhiteSibling(sourceRange, down);
// Either reached last sibling, or jumped over multi-line whitespace
if (sibling == null) {
info.toMove2 = null;
return true;
}
info.toMove = sourceRange;
info.toMove2 = getTargetRange(editor, sibling, down, sourceRange.firstElement);
return true;
}
}
@@ -0,0 +1,448 @@
package org.jetbrains.jet.plugin.codeInsight.upDownMover;
import com.intellij.codeInsight.editorActions.moveUpDown.LineRange;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetTokens;
public class JetExpressionMover extends AbstractJetUpDownMover {
public JetExpressionMover() {
}
private final static Class[] MOVABLE_ELEMENT_CLASSES = {JetExpression.class, JetWhenEntry.class, JetValueArgument.class, PsiComment.class};
private final static Class[] BLOCKLIKE_ELEMENT_CLASSES =
{JetBlockExpression.class, JetWhenExpression.class, JetClassBody.class, JetFile.class};
private final static Class[] FUNCTIONLIKE_ELEMENT_CLASSES =
{JetFunction.class, JetPropertyAccessor.class, JetClassInitializer.class};
@Nullable
private static PsiElement getStandaloneClosingBrace(@NotNull PsiFile file, @NotNull Editor editor) {
LineRange range = getLineRangeFromSelection(editor);
if (range.endLine - range.startLine != 1) return null;
int offset = editor.getCaretModel().getOffset();
Document document = editor.getDocument();
int line = document.getLineNumber(offset);
int lineStartOffset = document.getLineStartOffset(line);
String lineText = document.getText().substring(lineStartOffset, document.getLineEndOffset(line));
if (!lineText.trim().equals("}")) return null;
return file.findElementAt(lineStartOffset + lineText.indexOf('}'));
}
private static BraceStatus checkForMovableDownClosingBrace(
@NotNull PsiElement closingBrace,
@NotNull PsiElement block,
@NotNull Editor editor,
@NotNull MoveInfo info
) {
PsiElement current = block;
PsiElement nextElement = null;
PsiElement nextExpression = null;
do {
PsiElement sibling = firstNonWhiteElement(current.getNextSibling(), true);
if (sibling != null && nextElement == null) {
nextElement = sibling;
}
if (sibling instanceof JetExpression) {
nextExpression = sibling;
break;
}
current = current.getParent();
}
while (current != null && !(PsiTreeUtil.instanceOf(current, BLOCKLIKE_ELEMENT_CLASSES)));
if (nextExpression == null) return BraceStatus.NOT_MOVABLE;
Document doc = editor.getDocument();
info.toMove = new LineRange(closingBrace, closingBrace, doc);
info.toMove2 = new LineRange(nextElement, nextExpression);
info.indentSource = true;
return BraceStatus.MOVABLE;
}
private static BraceStatus checkForMovableUpClosingBrace(
@NotNull PsiElement closingBrace,
PsiElement block,
@NotNull Editor editor,
@NotNull MoveInfo info
) {
//noinspection unchecked
PsiElement prev = JetPsiUtil.getLastChildByType(block, JetExpression.class);
if (prev == null) return BraceStatus.NOT_MOVABLE;
Document doc = editor.getDocument();
info.toMove = new LineRange(closingBrace, closingBrace, doc);
info.toMove2 = new LineRange(prev, prev, doc);
info.indentSource = true;
return BraceStatus.MOVABLE;
}
private static enum BraceStatus {
NOT_FOUND,
MOVABLE,
NOT_MOVABLE
}
// Returns null if standalone closing brace is not found
private static BraceStatus checkForMovableClosingBrace(
@NotNull Editor editor,
@NotNull PsiFile file,
@NotNull MoveInfo info,
boolean down
) {
PsiElement closingBrace = getStandaloneClosingBrace(file, editor);
if (closingBrace == null) return BraceStatus.NOT_FOUND;
PsiElement blockLikeElement = closingBrace.getParent();
if (!(blockLikeElement instanceof JetBlockExpression)) return BraceStatus.NOT_MOVABLE;
PsiElement blockParent = blockLikeElement.getParent();
if (blockParent instanceof JetWhenEntry) return BraceStatus.NOT_FOUND;
if (PsiTreeUtil.instanceOf(blockParent, FUNCTIONLIKE_ELEMENT_CLASSES)) return BraceStatus.NOT_FOUND;
PsiElement enclosingExpression = PsiTreeUtil.getParentOfType(blockLikeElement, JetExpression.class);
if (enclosingExpression instanceof JetDoWhileExpression) return BraceStatus.NOT_MOVABLE;
if (enclosingExpression instanceof JetIfExpression) {
JetIfExpression ifExpression = (JetIfExpression) enclosingExpression;
if (blockLikeElement == ifExpression.getThen() && ifExpression.getElse() != null) return BraceStatus.NOT_MOVABLE;
}
return down
? checkForMovableDownClosingBrace(closingBrace, blockLikeElement, editor, info)
: checkForMovableUpClosingBrace(closingBrace, blockLikeElement, editor, info);
}
@Nullable
private static JetBlockExpression findClosestBlock(@NotNull PsiElement anchor, boolean down) {
PsiElement current = PsiTreeUtil.getParentOfType(anchor, JetBlockExpression.class);
while (current != null) {
PsiElement parent = current.getParent();
if (parent instanceof JetClassBody ||
parent instanceof JetClassInitializer ||
parent instanceof JetFunction ||
parent instanceof JetProperty) {
return null;
}
if (parent instanceof JetBlockExpression) return (JetBlockExpression) parent;
PsiElement sibling = down ? current.getNextSibling() : current.getPrevSibling();
if (sibling != null) {
//noinspection unchecked
JetBlockExpression block = JetPsiUtil.getOutermostJetElement(sibling, down, JetBlockExpression.class);
if (block != null) return block;
current = sibling;
}
else {
current = parent;
}
}
return null;
}
@Nullable
private static LineRange getExpressionTargetRange(@NotNull Editor editor, @NotNull PsiElement sibling, boolean down) {
PsiElement start = sibling;
PsiElement end = sibling;
// moving out of code block
if (sibling.getNode().getElementType() == (down ? JetTokens.RBRACE : JetTokens.LBRACE)) {
PsiElement parent = sibling.getParent();
if (!(parent instanceof JetBlockExpression || parent instanceof JetFunctionLiteral)) return null;
JetBlockExpression newBlock = findClosestBlock(sibling, down);
if (newBlock == null) return null;
if (PsiTreeUtil.isAncestor(newBlock, parent, true)) {
PsiElement outermostParent = JetPsiUtil.getOutermostParent(parent, newBlock, true);
if (down) {
end = outermostParent;
}
else {
start = outermostParent;
}
}
else {
if (down) {
end = newBlock.getLBrace();
}
else {
start = newBlock.getRBrace();
}
}
}
else {
// moving into code block
//noinspection unchecked
JetElement blockLikeElement = JetPsiUtil.getOutermostJetElement(sibling, down, JetBlockExpression.class, JetWhenExpression.class, JetClassBody.class);
if (blockLikeElement != null &&
!(PsiTreeUtil.instanceOf(blockLikeElement.getParent(), FUNCTIONLIKE_ELEMENT_CLASSES))) {
if (blockLikeElement instanceof JetWhenExpression) {
//noinspection unchecked
blockLikeElement = JetPsiUtil.getOutermostJetElement(blockLikeElement, down, JetBlockExpression.class);
}
if (blockLikeElement != null) {
if (down) {
end = JetPsiUtil.findChildByType(blockLikeElement, JetTokens.LBRACE);
}
else {
start = JetPsiUtil.findChildByType(blockLikeElement, JetTokens.RBRACE);
}
}
}
}
return start != null && end != null ? new LineRange(start, end, editor.getDocument()) : null;
}
@Nullable
private static LineRange getWhenEntryTargetRange(@NotNull Editor editor, @NotNull PsiElement sibling, boolean down) {
if (sibling.getNode().getElementType() == (down ? JetTokens.RBRACE : JetTokens.LBRACE) &&
PsiTreeUtil.getParentOfType(sibling, JetWhenEntry.class) == null) {
return null;
}
return new LineRange(sibling, sibling, editor.getDocument());
}
@Nullable
private LineRange getValueParamOrArgTargetRange(@NotNull Editor editor, @NotNull PsiElement elementToCheck, @NotNull PsiElement sibling, boolean down) {
PsiElement next = sibling;
if (next.getNode().getElementType() == JetTokens.COMMA) {
next = firstNonWhiteSibling(next, down);
}
LineRange range = (next instanceof JetParameter || next instanceof JetValueArgument)
? new LineRange(next, next, editor.getDocument())
: null;
if (range != null) {
parametersOrArgsToMove = new Pair<PsiElement, PsiElement>(elementToCheck, next);
}
return range;
}
@Nullable
private LineRange getTargetRange(
@NotNull Editor editor,
@Nullable PsiElement elementToCheck,
@NotNull PsiElement sibling,
boolean down
) {
if (elementToCheck instanceof JetParameter || elementToCheck instanceof JetValueArgument) {
return getValueParamOrArgTargetRange(editor, elementToCheck, sibling, down);
}
if (elementToCheck instanceof JetExpression || elementToCheck instanceof PsiComment) {
return getExpressionTargetRange(editor, sibling, down);
}
if (elementToCheck instanceof JetWhenEntry) {
return getWhenEntryTargetRange(editor, sibling, down);
}
return null;
}
@Override
protected boolean checkSourceElement(@NotNull PsiElement element) {
return PsiTreeUtil.instanceOf(element, MOVABLE_ELEMENT_CLASSES);
}
@Override
protected LineRange getElementSourceLineRange(@NotNull PsiElement element, @NotNull Editor editor, @NotNull LineRange oldRange) {
TextRange textRange = element.getTextRange();
if (editor.getDocument().getTextLength() < textRange.getEndOffset()) return null;
int startLine = editor.offsetToLogicalPosition(textRange.getStartOffset()).line;
int endLine = editor.offsetToLogicalPosition(textRange.getEndOffset()).line + 1;
return new LineRange(startLine, endLine);
}
@Nullable
private static PsiElement getMovableElement(@NotNull PsiElement element, boolean lookRight) {
PsiElement movableElement = PsiTreeUtil.getNonStrictParentOfType(element, MOVABLE_ELEMENT_CLASSES);
if (movableElement == null) return null;
if (isBracelessBlock(movableElement)) {
movableElement = firstNonWhiteElement(lookRight ? movableElement.getLastChild() : movableElement.getFirstChild(), !lookRight);
}
return movableElement;
}
private static boolean isLastOfItsKind(@NotNull PsiElement element, boolean down) {
return getSiblingOfType(element, down, element.getClass()) == null;
}
private static boolean isForbiddenMove(@NotNull PsiElement element, boolean down) {
if (element instanceof JetParameter || element instanceof JetValueArgument) {
return isLastOfItsKind(element, down);
}
return false;
}
private static boolean isBracelessBlock(@NotNull PsiElement element) {
if (!(element instanceof JetBlockExpression)) return false;
JetBlockExpression block = (JetBlockExpression) element;
return block.getLBrace() == null && block.getRBrace() == null;
}
protected static PsiElement adjustWhiteSpaceSibling(
@NotNull Editor editor,
@NotNull LineRange sourceRange,
@NotNull MoveInfo info,
boolean down
) {
PsiElement element = down ? sourceRange.lastElement : sourceRange.firstElement;
PsiElement sibling = down ? element.getNextSibling() : element.getPrevSibling();
PsiElement whiteSpaceTestSubject = sibling;
if (sibling == null) {
PsiElement parent = element.getParent();
if (parent != null && isBracelessBlock(parent)) {
whiteSpaceTestSubject = down ? parent.getNextSibling() : parent.getPrevSibling();
}
}
if (whiteSpaceTestSubject instanceof PsiWhiteSpace) {
Document doc = editor.getDocument();
TextRange spaceRange = whiteSpaceTestSubject.getTextRange();
int startLine = doc.getLineNumber(spaceRange.getStartOffset());
int endLine = doc.getLineNumber(spaceRange.getEndOffset());
if (endLine - startLine > 1) {
int nearLine = down ? sourceRange.endLine : sourceRange.startLine - 1;
info.toMove = sourceRange;
info.toMove2 = new LineRange(nearLine, nearLine + 1);
info.indentTarget = false;
return null;
}
if (sibling != null) {
sibling = firstNonWhiteElement(sibling, down);
}
}
if (sibling == null) {
info.toMove2 = null;
return null;
}
return sibling;
}
@Override
public boolean checkAvailable(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
parametersOrArgsToMove = null;
if (!super.checkAvailable(editor, file, info, down)) return false;
switch (checkForMovableClosingBrace(editor, file, info, down)) {
case NOT_MOVABLE: {
info.toMove2 = null;
return true;
}
case MOVABLE: return true;
default: break;
}
LineRange oldRange = info.toMove;
Pair<PsiElement, PsiElement> psiRange = getElementRange(editor, file, oldRange);
if (psiRange == null) return false;
//noinspection unchecked
PsiElement firstElement = getMovableElement(psiRange.getFirst(), false);
PsiElement lastElement = getMovableElement(psiRange.getSecond(), true);
if (firstElement == null || lastElement == null) return false;
if (isForbiddenMove(firstElement, down) || isForbiddenMove(lastElement, down)) {
info.toMove2 = null;
return true;
}
if ((firstElement instanceof JetParameter || firstElement instanceof JetValueArgument) && PsiTreeUtil.isAncestor(lastElement, firstElement, false)) {
lastElement = firstElement;
}
LineRange sourceRange = getSourceRange(firstElement, lastElement, editor, oldRange);
if (sourceRange == null) return false;
PsiElement sibling = adjustWhiteSpaceSibling(editor, sourceRange, info, down);
// Either reached last sibling, or jumped over multi-line whitespace
if (sibling == null) return true;
info.toMove = sourceRange;
info.toMove2 = getTargetRange(editor, sourceRange.firstElement, sibling, down);
return true;
}
@Nullable
private Pair<PsiElement, PsiElement> parametersOrArgsToMove;
private static PsiElement getComma(@NotNull PsiElement element) {
PsiElement sibling = firstNonWhiteSibling(element, true);
return sibling != null && (sibling.getNode().getElementType() == JetTokens.COMMA) ? sibling : null;
}
private static void fixCommaIfNeeded(@NotNull PsiElement element, boolean willBeLast) {
PsiElement comma = getComma(element);
if (willBeLast && comma != null) {
comma.delete();
}
else if (!willBeLast && comma == null) {
PsiElement parent = element.getParent();
assert parent != null;
parent.addAfter(JetPsiFactory.createComma(parent.getProject()), element);
}
}
@Override
public void beforeMove(@NotNull Editor editor, @NotNull MoveInfo info, boolean down) {
if (parametersOrArgsToMove != null) {
PsiElement element1 = parametersOrArgsToMove.first;
PsiElement element2 = parametersOrArgsToMove.second;
fixCommaIfNeeded(element1, down && isLastOfItsKind(element2, true));
fixCommaIfNeeded(element2, !down && isLastOfItsKind(element1, true));
//noinspection ConstantConditions
PsiDocumentManager.getInstance(editor.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument());
}
}
}
@@ -68,9 +68,9 @@ public final class DescriptorLookupConverter {
}
LookupElementBuilder element = LookupElementBuilder.create(
new JetLookupObject(descriptor, analyzer, declaration), descriptor.getName().getName());
new JetLookupObject(descriptor, analyzer, declaration), descriptor.getName().asString());
String presentableText = descriptor.getName().getName();
String presentableText = descriptor.getName().asString();
String typeText = "";
String tailText = "";
boolean tailTextGrayed = true;
@@ -36,7 +36,6 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.util.codeInsight.CommentUtilCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetToken;
@@ -103,7 +102,7 @@ public class JetKeywordCompletionContributor extends CompletionContributor {
return false;
}
return CommentUtilCore.isComment((PsiElement) element);
return JetPsiUtil.isInComment((PsiElement) element);
}
@Override
@@ -43,12 +43,12 @@ class ConvertedCode implements TextBlockTransferableData {
@Override
public int getOffsets(int[] offsets, int index) {
return 0;
return index;
}
@Override
public int setOffsets(int[] offsets, int index) {
return 0;
return index;
}
public String getData() {
@@ -227,7 +227,7 @@ public class JetImportOptimizer implements ImportOptimizer {
for (JetSimpleNameExpression nameExpression : simpleNameExpressions) {
Name referencedName = nameExpression.getReferencedNameAsName();
if (fqName == null) {
fqName = new FqName(referencedName.getName());
fqName = new FqName(referencedName.asString());
} else {
fqName = QualifiedNamesUtil.combine(fqName, referencedName);
}
@@ -27,9 +27,13 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.kdoc.lexer.KDocTokens;
import org.jetbrains.jet.plugin.JetLanguage;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.JetNodeTypes.*;
import static org.jetbrains.jet.lexer.JetTokens.*;
@@ -38,6 +42,7 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
* @see Block for good JavaDoc documentation
*/
public class JetBlock extends AbstractBlock {
private static final int KDOC_COMMENT_INDENT = 1;
private final ASTAlignmentStrategy myAlignmentStrategy;
private final Indent myIndent;
private final CodeStyleSettings mySettings;
@@ -208,6 +213,9 @@ public class JetBlock extends AbstractBlock {
}
return new ChildAttributes(Indent.getContinuationIndent(), null);
}
else if (type == DOC_COMMENT) {
return new ChildAttributes(Indent.getSpaceIndent(KDOC_COMMENT_INDENT), null);
}
if (isIncomplete()) {
return super.getChildAttributes(newChildIndex);
@@ -321,6 +329,11 @@ public class JetBlock extends AbstractBlock {
.in(PROPERTY, FUN)
.notForType(BLOCK)
.set(Indent.getContinuationWithoutFirstIndent()),
ASTIndentStrategy.forNode("KDoc comment indent")
.in(DOC_COMMENT)
.forType(KDocTokens.LEADING_ASTERISK, KDocTokens.END)
.set(Indent.getSpaceIndent(KDOC_COMMENT_INDENT)),
};
@Nullable
@@ -34,8 +34,9 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder {
@NotNull
@Override
public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
PsiFile containingFile = element.getContainingFile().getViewProvider().getPsi(JetLanguage.INSTANCE);
JetBlock block = new JetBlock(
element.getNode(), ASTAlignmentStrategy.getNullStrategy(), Indent.getNoneIndent(), null, settings,
containingFile.getNode(), ASTAlignmentStrategy.getNullStrategy(), Indent.getNoneIndent(), null, settings,
createSpacingBuilder(settings));
return FormattingModelProvider.createFormattingModelForPsiFile(
@@ -53,6 +54,7 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder {
.between(IMPORT_DIRECTIVE, IMPORT_DIRECTIVE).lineBreakInCode()
.after(IMPORT_DIRECTIVE).blankLines(1)
.before(DOC_COMMENT).lineBreakInCode()
.before(FUN).lineBreakInCode()
.before(PROPERTY).lineBreakInCode()
.between(FUN, FUN).blankLines(1)
@@ -247,7 +247,7 @@ public class DeprecatedAnnotationVisitor extends AfterAnalysisHighlightingVisito
private static String getDescriptorString(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof ClassDescriptor) {
return DescriptorUtils.getFQName(descriptor).getFqName();
return DescriptorUtils.getFQName(descriptor).asString();
}
else if (descriptor instanceof ConstructorDescriptor) {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
@@ -166,7 +166,7 @@ public class IdeRenderers {
DeclarationDescriptor containingDeclaration = funDescriptor.getContainingDeclaration();
if (containingDeclaration != null) {
FqNameUnsafe fqName = DescriptorUtils.getFQName(containingDeclaration);
stringBuilder.append(FqName.ROOT.equalsTo(fqName) ? "root package" : fqName.getFqName());
stringBuilder.append(FqName.ROOT.equalsTo(fqName) ? "root package" : fqName.asString());
}
stringBuilder.append("</li>");
}
@@ -54,7 +54,7 @@ public class JetColorSettingsPage implements ColorSettingsPage {
"\n" +
"/**\n" +
" * Doc comment here for `SomeClass`\n" +
" * @see Iterator#next()\n" +
" * <KDOC_TAG>@see</KDOC_TAG> Iterator#next()\n" +
" */\n" +
"[<ANNOTATION>Deprecated</ANNOTATION>]\n" +
"<BUILTIN_ANNOTATION>public</BUILTIN_ANNOTATION> class <CLASS>MyClass</CLASS><<BUILTIN_ANNOTATION>out</BUILTIN_ANNOTATION> <TYPE_PARAMETER>T</TYPE_PARAMETER> : <TRAIT>Iterable</TRAIT><<TYPE_PARAMETER>T</TYPE_PARAMETER>>>(var <INSTANCE_PROPERTY><MUTABLE_VARIABLE>prop1</MUTABLE_VARIABLE></INSTANCE_PROPERTY> : Int) {\n" +
@@ -126,6 +126,8 @@ public class JetColorSettingsPage implements ColorSettingsPage {
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.block.comment"), JetHighlightingColors.BLOCK_COMMENT),
new AttributesDescriptor(JetBundle.message("options.jet.attribute.descriptor.kdoc.comment"), JetHighlightingColors.DOC_COMMENT),
new AttributesDescriptor(JetBundle.message("options.jet.attribute.descriptor.kdoc.tag"), JetHighlightingColors.KDOC_TAG),
new AttributesDescriptor(JetBundle.message("options.jet.attribute.descriptor.kdoc.value"), JetHighlightingColors.KDOC_TAG_VALUE),
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.class"), JetHighlightingColors.CLASS),
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.type.parameter"), JetHighlightingColors.TYPE_PARAMETER),
@@ -23,7 +23,7 @@ import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lexer.JetLexer;
import org.jetbrains.jet.kdoc.lexer.KDocTokens;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.HashMap;
@@ -34,7 +34,7 @@ public class JetHighlighter extends SyntaxHighlighterBase {
@NotNull
public Lexer getHighlightingLexer() {
return new JetLexer();
return new JetHighlightingLexer();
}
@NotNull
@@ -83,6 +83,9 @@ public class JetHighlighter extends SyntaxHighlighterBase {
keys.put(JetTokens.BLOCK_COMMENT, JetHighlightingColors.BLOCK_COMMENT);
keys.put(JetTokens.DOC_COMMENT, JetHighlightingColors.DOC_COMMENT);
fillMap(keys, KDocTokens.CONTENT_TOKENS, JetHighlightingColors.DOC_COMMENT);
keys.put(KDocTokens.TAG_NAME, JetHighlightingColors.KDOC_TAG);
keys.put(TokenType.BAD_CHARACTER, JetHighlightingColors.BAD_CHARACTER);
}
}

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