Daniil Ovchinnikov
2016-03-28 14:03:34 +03:00
23 changed files with 1195 additions and 32 deletions
@@ -0,0 +1,5 @@
<html>
<body>
This inspection reports method calls that can be replaced with operators.
</body>
</html>
@@ -46,7 +46,9 @@ parameter.can.be.final.tooltip=Parameter ''{0}'' can be final
groovy.probable.bugs=Probable bugs
equals.between.inconvertible.types='equals()' between objects of inconvertible types
equals.between.inconvertible.types.tooltip=<code>{0}</code> between objects of inconvertible types ''{1}'' and ''{2}''
convert.to.operator=Change to operator
convert.to.operator.double.negation.option=Use double negation (i.e. !!)
convert.to.operator.compareto.equality.option=Change compareTo equality to equals (i.e. ==)
unassigned.access=Variable Not Assigned
unassigned.access.short.name=VariableNotAssigned
unassigned.access.tooltip=Variable ''{0}'' might not be assigned
@@ -61,7 +63,7 @@ no.type.specified=No type specified
dynamic.element=Dynamic Element
########################################################################################################################
# InpectorGroovy properties
# InspectorGroovy properties
########################################################################################################################
pointless.boolean.problem.descriptor=#ref can be simplified to ''{0}'' #loc
pointless.arithmetic.error.message=#ref can be replaced with ''{0}'' #loc
@@ -0,0 +1,113 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiModifierListOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.BaseInspection;
import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor;
import org.jetbrains.plugins.groovy.codeInspection.GroovyFix;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.ReplacementData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations.Transformation;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations.Transformations;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import javax.swing.*;
import java.util.Map;
import static com.intellij.codeInspection.ProblemHighlightType.WEAK_WARNING;
import static org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle.message;
public class ChangeToOperatorInspection extends BaseInspection {
private static final Map<String, Transformation> TRANSFORMATIONS = Transformations.get();
public boolean useDoubleNegation = true;
public boolean shouldChangeCompareToEqualityToEquals = true;
@NotNull
@Override
protected BaseInspectionVisitor buildVisitor() {
return new BaseInspectionVisitor() {
@Override
public void visitMethodCallExpression(GrMethodCallExpression methodCallExpression) {
super.visitMethodCallExpression(methodCallExpression);
processMethodCall(methodCallExpression);
}
private void processMethodCall(GrMethodCallExpression methodCallExpression) {
PsiMethod method = methodCallExpression.resolveMethod();
if (!isValid(method)) return;
String methodName = method.getName();
Transformation transformation = TRANSFORMATIONS.get(methodName);
if (transformation == null) return;
// TODO apply transformation recursively
ReplacementData replacement = transformation.transform(methodCallExpression,
new OptionsData(useDoubleNegation, shouldChangeCompareToEqualityToEquals));
registerFixIfValid(replacement);
}
private boolean isValid(PsiModifierListOwner method) {
return ((method != null) && !method.hasModifierProperty(PsiModifier.STATIC));
}
private void registerFixIfValid(@Nullable ReplacementData replacement) {
if (replacement == null) return;
String message = getMessage();
LocalQuickFix[] quickFixes = {getFix(message, replacement.getReplacement())};
registerError(replacement.getExpression(), message, quickFixes, WEAK_WARNING);
}
private GroovyFix getFix(@NotNull final String message, final String replacement) {
return new GroovyFix() {
@NotNull
@Override
public String getName() {
return message;
}
@Override
protected void doFix(Project project, ProblemDescriptor descriptor) {
replaceExpression((GrExpression)descriptor.getPsiElement(), replacement);
}
};
}
};
}
public String getMessage() {
return message("convert.to.operator");
}
@Override
public JComponent createOptionsPanel() {
MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this);
optionsPanel.addCheckbox(message("convert.to.operator.double.negation.option"), "useDoubleNegation");
optionsPanel.addCheckbox(message("convert.to.operator.compareto.equality.option"), "shouldChangeCompareToEqualityToEquals");
return optionsPanel;
}
}
@@ -0,0 +1,146 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.impl.utils.ParenthesesUtils;
import static org.jetbrains.plugins.groovy.lang.psi.impl.utils.BoolUtils.isNegation;
import static org.jetbrains.plugins.groovy.lang.psi.impl.utils.ComparisonUtils.isComparison;
public final class MethodCallData {
private final PsiElement backingElement;
private boolean isNegated;
private GrExpression base;
private GrExpression[] arguments;
private IElementType comparison;
@Nullable
public static MethodCallData create(@NotNull PsiElement backingElement) {
return Builder.build(backingElement);
}
private MethodCallData(@NotNull PsiElement backingElement) {
this.backingElement = backingElement;
}
@NotNull
public PsiElement getBackingElement() {
return backingElement;
}
public boolean isNegated() {
return isNegated;
}
@NotNull
public String getBase() {
return base.getText();
}
@Nullable
public String getArgument(int i) {
return (i >= arguments.length) ? null
: arguments[i].getText();
}
@Nullable
public IElementType getComparison() {
return comparison;
}
private static final class Builder {
@Nullable
public static MethodCallData build(@NotNull PsiElement backingElement) {
MethodCallData result = new MethodCallData(backingElement);
PsiElement element = backingElement;
element = handleNegation(result, element);
element = handleComparison(result, element);
element = handleMethodCall(result, element);
return (element == null) ? null
: result;
}
private static PsiElement handleNegation(MethodCallData result, @Nullable PsiElement element) {
if (element == null) return null;
result.isNegated = isNegation(element);
if (result.isNegated) element = ((GrUnaryExpression)element).getOperand();
return element;
}
private static PsiElement handleComparison(MethodCallData result, @Nullable PsiElement element) {
if (element == null) return null;
if (isComparison(element)) {
GrBinaryExpression relationalExpression = (GrBinaryExpression)element;
element = relationalExpression.getLeftOperand();
result.comparison = relationalExpression.getOperationTokenType();
}
return element;
}
@Nullable
private static PsiElement handleMethodCall(MethodCallData result, PsiElement element) {
if (!(element instanceof GrMethodCall)) return null;
GrMethodCall methodCall = (GrMethodCall)element;
GrReferenceExpression invokedExpression = (GrReferenceExpression)methodCall.getInvokedExpression();
GrExpression qualifierExpression = invokedExpression.getQualifierExpression();
if (qualifierExpression == null) return null;
result.base = addParenthesesIfNeeded(qualifierExpression);
result.arguments = addParenthesesIfNeeded(methodCall.getExpressionArguments());
return element;
}
private static GrExpression addParenthesesIfNeeded(@NotNull GrExpression expression) {
return needsParentheses(expression) ? createParenthesizedExpr(expression)
: expression;
}
private static boolean needsParentheses(@NotNull GrExpression expression) {
return ParenthesesUtils.getPrecedence(expression) >= ParenthesesUtils.TYPE_CAST_PRECEDENCE;
}
private static GrExpression[] addParenthesesIfNeeded(GrExpression[] expressions) {
GrExpression[] results = new GrExpression[expressions.length];
for (int i = 0; i < results.length; i++) {
results[i] = addParenthesesIfNeeded(expressions[i]);
}
return results;
}
public static GrExpression createParenthesizedExpr(@NotNull GrExpression expression) {
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(expression.getProject());
return factory.createParenthesizedExpr(expression);
}
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data;
public final class OptionsData {
private final boolean useDoubleNegation;
private final boolean shouldChangeCompareToEqualityToEquals;
public OptionsData(boolean useDoubleNegation, boolean shouldChangeCompareToEqualityToEquals) {
this.useDoubleNegation = useDoubleNegation;
this.shouldChangeCompareToEqualityToEquals = shouldChangeCompareToEqualityToEquals;
}
public boolean useDoubleNegation() {
return useDoubleNegation;
}
public boolean shouldChangeCompareToEqualityToEquals() {
return shouldChangeCompareToEqualityToEquals;
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
public final class ReplacementData {
private final GrExpression element;
private final String replacement;
public ReplacementData(@NotNull GrExpression element, @NotNull String replacement) {
this.element = element;
this.replacement = replacement;
}
public GrExpression getExpression() {
return element;
}
public String getExpressionText() {
return element.getText();
}
public String getReplacement() {
return replacement;
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrIfStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mLNOT;
import static org.jetbrains.plugins.groovy.lang.psi.impl.utils.BoolUtils.isNegation;
class AsBooleanTransformation extends UnaryTransformation {
public static final String NEGATION = mLNOT.toString();
public static final String DOUBLE_NEGATION = NEGATION + NEGATION;
public AsBooleanTransformation() {
super(null);
}
@Override
protected GrExpression getExpandedElement(GrMethodCallExpression callExpression) {
PsiElement parent = callExpression.getParent();
if (isNegation(parent)) {
return (GrExpression)parent;
}
else {
return super.getExpandedElement(callExpression);
}
}
@Override
@Nullable
protected String getPrefix(MethodCallData methodInfo, OptionsData optionsData) {
if (methodInfo.isNegated()) {
return NEGATION;
}
else if (isImplicitlyBoolean(methodInfo)) {
return "";
}
else if (optionsData.useDoubleNegation()) {
return DOUBLE_NEGATION;
}
else {
return null;
}
}
private static boolean isImplicitlyBoolean(MethodCallData methodInfo) {
return methodInfo.getBackingElement().getParent() instanceof GrIfStatement;
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import static java.lang.String.format;
/**
* e.g.
* a.equals(b) → (a == b)
* !a.equals(b) → (a != b)
*/
public class BinaryTransformation extends Transformation {
public BinaryTransformation(@Nullable IElementType operator) {
super(operator);
}
@Override
@Nullable
public String getReplacement(MethodCallData methodInfo, OptionsData optionsData) {
String lhs = getLhs(methodInfo);
IElementType operator = getOperator(methodInfo, optionsData);
String rhs = getRhs(methodInfo);
if (lhs == null || operator == null || rhs == null) return null;
return format("%s %s %s", lhs, operator, rhs);
}
@Nullable
protected String getLhs(MethodCallData methodInfo) {
return methodInfo.getBase();
}
@Nullable
protected IElementType getOperator(MethodCallData methodInfo, OptionsData optionsData) {
return operator;
}
@Nullable
protected String getRhs(MethodCallData methodInfo) {
return methodInfo.getArgument(0);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mLPAREN;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mRPAREN;
class CallTransformation extends UnaryTransformation {
public static final String EMPTY_PARENS = mLPAREN.toString() + mRPAREN;
public CallTransformation() {
super(null);
}
@Override
public String getReplacement(MethodCallData call, OptionsData options) {
return super.getReplacement(call, options) + EMPTY_PARENS;
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import static com.google.common.base.Objects.firstNonNull;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*;
import static org.jetbrains.plugins.groovy.lang.psi.impl.utils.ComparisonUtils.isComparison;
class CompareToTransformation extends BinaryTransformation {
public CompareToTransformation() {
super(null);
}
@Override
protected GrExpression getExpandedElement(GrMethodCallExpression callExpression) {
PsiElement parent = callExpression.getParent();
return isComparison(parent) ? (GrExpression)parent
: super.getExpandedElement(callExpression);
}
@Override
protected IElementType getOperator(MethodCallData methodInfo, OptionsData optionsData) {
IElementType comparison = methodInfo.getComparison();
if (shouldChangeCompareToEqualityToEquals(optionsData, comparison)) {
return firstNonNull(comparison, mCOMPARE_TO);
}
else {
return null;
}
}
private static boolean shouldChangeCompareToEqualityToEquals(OptionsData optionsData, IElementType comparison) {
return !isEquality(comparison) || optionsData.shouldChangeCompareToEqualityToEquals();
}
private static boolean isEquality(IElementType comparison) {
return (comparison == mNOT_EQUAL) || (comparison == mEQUAL);
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mEQUAL;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mNOT_EQUAL;
import static org.jetbrains.plugins.groovy.lang.psi.impl.utils.BoolUtils.isNegation;
class EqualsTransformation extends BinaryTransformation {
public EqualsTransformation() {
super(null);
}
@Override
protected GrExpression getExpandedElement(GrMethodCallExpression callExpression) {
PsiElement parent = callExpression.getParent();
return isNegation(parent) ? (GrExpression)parent
: super.getExpandedElement(callExpression);
}
@Override
@Nullable
protected IElementType getOperator(MethodCallData methodInfo, OptionsData optionsData) {
return methodInfo.isNegated() ? mNOT_EQUAL
: mEQUAL;
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import static java.lang.String.format;
class GetAtTransformation extends Transformation {
public GetAtTransformation() {
super(null);
}
@Override
@Nullable
public String getReplacement(MethodCallData methodInfo, OptionsData optionsData) {
String argument = methodInfo.getArgument(0);
if (argument == null) return null;
return format("%s[%s]",
methodInfo.getBase(), argument);
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
class IsCaseTransformation extends BinaryTransformation {
public IsCaseTransformation() {
super(GroovyTokenTypes.kIN);
}
@Override
@Nullable
protected String getLhs(MethodCallData methodInfo) {
return super.getRhs(methodInfo);
}
@Override
@Nullable
protected String getRhs(MethodCallData methodInfo) {
return super.getLhs(methodInfo);
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import static java.lang.String.format;
class PutAtTransformation extends Transformation {
private final Transformation getAtTransformation;
public PutAtTransformation(Transformation getAtTransformation) {
super(null);
this.getAtTransformation = getAtTransformation;
}
@Override
@Nullable
public String getReplacement(MethodCallData methodInfo, OptionsData optionsData) {
String argument = methodInfo.getArgument(1);
if (argument == null) return null;
return format("%s = %s",
getAtTransformation.getReplacement(methodInfo, optionsData), argument);
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.ReplacementData;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
public abstract class Transformation {
@Nullable
protected final IElementType operator;
public Transformation(@Nullable IElementType operator) {
this.operator = operator;
}
@Nullable
public ReplacementData transform(GrMethodCallExpression callExpression, OptionsData optionsData) {
GrExpression element = getExpandedElement(callExpression);
MethodCallData methodInfo = MethodCallData.create(element);
if (methodInfo == null) return null;
String replacement = getReplacement(methodInfo, optionsData);
if (replacement == null) return null;
return new ReplacementData(element, replacement);
}
protected GrExpression getExpandedElement(GrMethodCallExpression callExpression) {
return callExpression;
}
@Nullable
public abstract String getReplacement(MethodCallData methodInfo, OptionsData optionsData);
}
@@ -0,0 +1,82 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtil.ImmutableMapBuilder;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType;
import java.util.Map;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*;
import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.HardcodedGroovyMethodConstants.*;
public class Transformations {
private final ImmutableMapBuilder<String, Transformation> result = ContainerUtil.immutableMapBuilder();
public static Map<String, Transformation> get() {
Transformations builder = new Transformations();
return builder.build();
}
private Transformations() {
addUnary();
addBinary();
addCustom();
}
private void addUnary() {
result.put(BITWISE_NEGATE, new UnaryTransformation(mBNOT));
result.put(NEGATIVE, new UnaryTransformation(mMINUS));
result.put(POSITIVE, new UnaryTransformation(mPLUS));
result.put(NEXT, new UnaryTransformation(mINC));
result.put(PREVIOUS, new UnaryTransformation(mDEC));
result.put(AS_BOOLEAN, new AsBooleanTransformation());
result.put(CALL, new CallTransformation());
}
private void addBinary() {
result.put(PLUS, new BinaryTransformation(mPLUS));
result.put(MINUS, new BinaryTransformation(mMINUS));
result.put(MULTIPLY, new BinaryTransformation(mSTAR));
result.put(POWER, new BinaryTransformation(mSTAR_STAR));
result.put(DIV, new BinaryTransformation(mDIV));
result.put(MOD, new BinaryTransformation(mMOD));
result.put(OR, new BinaryTransformation(mBOR));
result.put(AND, new BinaryTransformation(mBAND));
result.put(XOR, new BinaryTransformation(mBXOR));
result.put(LEFT_SHIFT, new BinaryTransformation(new GroovyElementType("<<")));
result.put(RIGHT_SHIFT, new BinaryTransformation(new GroovyElementType(">>")));
result.put(RIGHT_SHIFT_UNSIGNED, new BinaryTransformation(new GroovyElementType(">>>")));
result.put(AS_TYPE, new BinaryTransformation(kAS));
result.put(IS_CASE, new IsCaseTransformation());
result.put(EQUALS, new EqualsTransformation());
result.put(COMPARE_TO, new CompareToTransformation());
}
private void addCustom() {
Transformation getAtTransformation = new GetAtTransformation();
result.put(GET_AT, getAtTransformation);
result.put(PUT_AT, new PutAtTransformation(getAtTransformation));
}
private Map<String, Transformation> build() {
return result.build();
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.codeInspection.changeToOperator.transformations;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.MethodCallData;
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.data.OptionsData;
import static com.google.common.base.Objects.firstNonNull;
/**
* e.g.
* !a.asBoolean() → !a
* a.asBoolean() → !!a
* if(a.asBoolean()) → if(a)
*/
public class UnaryTransformation extends Transformation {
public UnaryTransformation(@Nullable IElementType operator) {
super(operator);
}
@Override
@Nullable
public String getReplacement(MethodCallData call, OptionsData options) {
String prefix = getPrefix(call, options);
String base = call.getBase();
if ((prefix == null) || (base == null)) return null;
return prefix + base;
}
@Nullable
protected String getPrefix(MethodCallData call, OptionsData optionsData) {
return firstNonNull(operator, "").toString();
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions;
import com.siyeh.HardcodedMethodConstants;
import org.jetbrains.annotations.NonNls;
@NonNls
public class HardcodedGroovyMethodConstants {
public static final String COMPARE_TO = HardcodedMethodConstants.COMPARE_TO;
public static final String EQUALS = HardcodedMethodConstants.EQUALS;
public static final String NEXT = HardcodedMethodConstants.NEXT;
public static final String AND = "and";
public static final String AS_BOOLEAN = "asBoolean";
public static final String AS_TYPE = "asType";
public static final String BITWISE_NEGATE = "bitwiseNegate";
public static final String CALL = "call";
public static final String DIV = "div";
public static final String GET_AT = "getAt";
public static final String IS_CASE = "isCase";
public static final String LEFT_SHIFT = "leftShift";
public static final String MINUS = "minus";
public static final String MOD = "mod";
public static final String MULTIPLY = "multiply";
public static final String NEGATIVE = "negative";
public static final String OR = "or";
public static final String PLUS = "plus";
public static final String POSITIVE = "positive";
public static final String POWER = "power";
public static final String PREVIOUS = "previous";
public static final String PUT_AT = "putAt";
public static final String RIGHT_SHIFT = "rightShift";
public static final String RIGHT_SHIFT_UNSIGNED = "rightShiftUnsigned";
public static final String XOR = "xor";
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,6 +56,8 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import java.util.Iterator;
import java.util.Map;
import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.HardcodedGroovyMethodConstants.*;
/**
* @author ven
*/
@@ -134,33 +136,33 @@ public class TypesUtil {
private static final Map<IElementType, String> ourUnaryOperationsToOperatorNames = new HashMap<IElementType, String>();
static {
ourOperationsToOperatorNames.put(GroovyTokenTypes.mPLUS, "plus");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mMINUS, "minus");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mBAND, "and");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mBOR, "or");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mBXOR, "xor");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mDIV, "div");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mMOD, "mod");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mSTAR, "multiply");
ourOperationsToOperatorNames.put(GroovyTokenTypes.kAS, "asType");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mCOMPARE_TO, "compareTo");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mGT, "compareTo");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mGE, "compareTo");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mLT, "compareTo");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mLE, "compareTo");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mSTAR_STAR, "power");
ourOperationsToOperatorNames.put(GroovyElementTypes.COMPOSITE_LSHIFT_SIGN, "leftShift");
ourOperationsToOperatorNames.put(GroovyElementTypes.COMPOSITE_RSHIFT_SIGN, "rightShift");
ourOperationsToOperatorNames.put(GroovyElementTypes.COMPOSITE_TRIPLE_SHIFT_SIGN, "rightShiftUnsigned");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mEQUAL, "equals");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mNOT_EQUAL, "equals");
ourOperationsToOperatorNames.put(GroovyTokenTypes.mPLUS, PLUS);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mMINUS, MINUS);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mBAND, AND);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mBOR, OR);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mBXOR, XOR);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mDIV, DIV);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mMOD, MOD);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mSTAR, MULTIPLY);
ourOperationsToOperatorNames.put(GroovyTokenTypes.kAS, AS_TYPE);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mCOMPARE_TO, COMPARE_TO);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mGT, COMPARE_TO);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mGE, COMPARE_TO);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mLT, COMPARE_TO);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mLE, COMPARE_TO);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mSTAR_STAR, POWER);
ourOperationsToOperatorNames.put(GroovyElementTypes.COMPOSITE_LSHIFT_SIGN, LEFT_SHIFT);
ourOperationsToOperatorNames.put(GroovyElementTypes.COMPOSITE_RSHIFT_SIGN, RIGHT_SHIFT);
ourOperationsToOperatorNames.put(GroovyElementTypes.COMPOSITE_TRIPLE_SHIFT_SIGN, RIGHT_SHIFT_UNSIGNED);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mEQUAL, EQUALS);
ourOperationsToOperatorNames.put(GroovyTokenTypes.mNOT_EQUAL, EQUALS);
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mLNOT, "asBoolean");
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mPLUS, "positive");
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mMINUS, "negative");
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mDEC, "previous");
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mINC, "next");
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mBNOT, "bitwiseNegate");
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mLNOT, AS_BOOLEAN);
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mPLUS, POSITIVE);
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mMINUS, NEGATIVE);
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mDEC, PREVIOUS);
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mINC, NEXT);
ourUnaryOperationsToOperatorNames.put(GroovyTokenTypes.mBNOT, BITWISE_NEGATE);
}
private static final TObjectIntHashMap<String> TYPE_TO_RANK = new TObjectIntHashMap<String>();
@@ -15,6 +15,7 @@
*/
package org.jetbrains.plugins.groovy.lang.psi.impl.utils;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
@@ -64,7 +65,7 @@ public class BoolUtils {
return null;
}
public static boolean isNegation(GrExpression exp) {
public static boolean isNegation(@Nullable PsiElement exp) {
if (!(exp instanceof GrUnaryExpression)) {
return false;
}
@@ -15,10 +15,10 @@
*/
package org.jetbrains.plugins.groovy.lang.psi.impl.utils;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import java.util.HashMap;
import java.util.Map;
@@ -54,7 +54,7 @@ public class ComparisonUtils {
s_invertedComparisons.put(GroovyTokenTypes.mLE, ">");
}
public static boolean isComparison(GrExpression exp) {
public static boolean isComparison(PsiElement exp) {
if (!(exp instanceof GrBinaryExpression)) {
return false;
}
+4
View File
@@ -799,6 +799,10 @@
displayName="Java-style property access"
groupName="Style" enabledByDefault="false" level="WARNING"
implementationClass="org.jetbrains.plugins.groovy.codeInspection.style.JavaStylePropertiesInvocationInspection"/>
<localInspection language="Groovy" groupPath="Groovy" shortName="ChangeToOperator"
displayName="Change to operator"
groupName="Style" enabledByDefault="true" level="WARNING"
implementationClass="org.jetbrains.plugins.groovy.codeInspection.changeToOperator.ChangeToOperatorInspection"/>
<localInspection language="Groovy" groupPath="Groovy" shortName="GroovyAccessToStaticFieldLockedOnInstance"
displayName="Access to static field locked on instance data"
groupName="Threading issues" enabledByDefault="true" level="WARNING"
@@ -0,0 +1,193 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.inspections
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.intellij.lang.annotations.Language
import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.ChangeToOperatorInspection
import java.util.regex.Pattern
import static org.jetbrains.plugins.groovy.GroovyFileType.GROOVY_FILE_TYPE
import static org.jetbrains.plugins.groovy.util.TestUtils.CARET_MARKER
public class GrChangeToOperatorTest extends LightCodeInsightFixtureTestCase {
def inspection = new ChangeToOperatorInspection()
void testSimpleUnaryExpression() {
assertValid(/a.bitwiseNegate()/, /~a/)
assertValid(/a.negative()/, /-a/)
assertValid(/a.positive()/, /+a/)
assertValid(/a.call()/, /a()/)
assertValid(/a.next()/, /++a/)
assertValid(/a.previous()/, /--a/)
}
void testNegatableUnaryExpression() {
assertValid(/a.asBoolean()/, /!!a/)
assertValid(/!a.asBoolean()/, /!a/)
assertValid(/if (${_}a.asBoolean()${_});/, /a/)
assertValid(/if (${_}!a.asBoolean()${_});/, /!a/)
}
// TODO
void notYetTestable_testComplexNegatableUnaryExpression() {
assertValid(/if (${_}'a'.intern().asBoolean()${_});/, /'a'.intern()/)
}
void testNegatedOption() {
inspection.useDoubleNegation = false
assertValid(/a.asBoolean()/)
assertValid(/!a.asBoolean()/, /!a/)
assertValid(/if (${_}a.asBoolean()${_});/, /a/)
assertValid(/if (${_}!a.asBoolean()${_});/, /!a/)
}
// TODO
void notYetTestable_testComplexNegatedOption() {
inspection.useDoubleNegation = false
assertValid(/if (${_}'a'.intern().asBoolean()${_});/, /'a'.intern()/)
}
void testSimpleBinaryExpression() {
assertValid(/a.minus(b)/, /a - b/)
assertValid(/a.plus(b)/, /a + b/)
assertValid(/a.power(b)/, /a**b/)
assertValid(/a.div(b)/, $/a / b/$)
assertValid(/a.mod(b)/, /a % b/)
assertValid(/a.or(b)/, /a | b/)
assertValid(/a.and(b)/, /a & b/)
assertValid(/a.xor(b)/, /a ^ b/)
assertValid(/a.leftShift(b)/, /a << b/)
assertValid(/a.rightShift(b)/, /a >> b/)
assertValid(/a.rightShiftUnsigned(b)/, /a >>> b/)
assertValid(/a.asType(String)/, /a as String/)
assertValid(/a.multiply(b)/, /a * b/)
assertValid(/(a.toString() as Operators).minus(b.hashCode())/, /(a.toString() as Operators) - b.hashCode()/)
assertValid(/!${_}a.asType(String)${_}/, /(a as String)/)
assertValid(/${_}a.xor((a.b+1) == b)${_} == a/, /(a ^ ((a.b + 1) == b))/)
}
// TODO
void notYetTestable_testComplexBinaryExpression() {
assertValid(/b.isCase(a)/, /a in b/)
assertValid(/if (${_}[1,2,3].isCase(2-1)${_});/, /(2 - 1) in [1,2,3]/)
assertValid(/def x = ${_}"1".plus(1)${_}/, /"1" + 1/)
assertValid(/("1" + 1).plus(1)/, /("1" + 1) + 1/)
assertValid(/!a.toString().asBoolean()/, /!a.toString()/)
}
void testNegatableBinaryExpression() {
assertValid(/a.equals(b)/, /a == b/)
assertValid(/!a.equals(b)/, /a != b/)
}
// TODO
void notYetTestable_testComplexNegatableBinaryExpression() {
assertValid(/!(1.toString().replace('1', '2')+"").equals(2.toString())/, /(1.toString().replace('1', '2') + "") != 2.toString()/)
}
void testCompareTo() {
assertValid(/a.compareTo(b)/, /a <=> b/)
assertValid(/a.compareTo(b) < 0/, /a < b/)
assertValid(/a.compareTo(b) <= 0/, /a <= b/)
assertValid(/a.compareTo(b) == 0/, /a == b/)
assertValid(/a.compareTo(b) != 0/, /a != b/)
assertValid(/a.compareTo(b) >= 0/, /a >= b/)
assertValid(/a.compareTo(b) > 0/, /a > b/)
assertValid(/if (${_}(2-1).compareTo(b) > 0${_});/, /(2 - 1) > b/)
}
void testCompareToOption() {
inspection.shouldChangeCompareToEqualityToEquals = false
assertValid(/a.compareTo(b) == 0/)
assertValid(/a.compareTo(b) != 0/)
}
void testGetAndPut() {
assertValid(/a.getAt(b)/, /a[b]/)
assertValid(/a.putAt(b, 'c')/, /a[b] = 'c'/)
assertValid(/a.putAt(b, 'c'*2)/, /a[b] = ('c' * 2)/)
}
final _ = '/*placeholder*/'
@Language('Groovy') final DECLARATIONS = '''
@SuppressWarnings("GrMethodMayBeStatic")
class Operators {
def bitwiseNegate() { null }
def negative() { null }
def positive() { null }
def call() { null }
def next() { null }
def previous() { null }
def plus(b) { null }
def minus(b) { null }
def multiply(b) { null }
def power(b) { null }
def div(b) { null }
def mod(b) { null }
def or(b) { null }
def and(b) { null }
def xor(b) { null }
def leftShift(b) { null }
def rightShift(b) { null }
def rightShiftUnsigned(b) { null }
def asType(b) { null }
def getAt(b) { null }
def putAt(b, c) { null }
boolean asBoolean() { true }
boolean isCase(b) { true }
boolean equals(b) { true }
int compareTo(b) { 0 }
}
def (Operators a, Operators b) = [null, null]
'''
private void assertValid(@Language('Groovy') String text, @Language('Groovy') String methodReplacement) {
def (prefix, method, suffix) = getMessage(text)
configure("${prefix}${CARET_MARKER}${method}${suffix}")
myFixture.launchAction(myFixture.findSingleIntention(inspection.getMessage()))
myFixture.checkResult("${DECLARATIONS} ${prefix}${methodReplacement}${suffix}")
}
private void assertValid(@Language('Groovy') String text) {
configure(text)
assertEmpty myFixture.getAvailableIntentions()
}
private configure(@Language('Groovy') String text) {
myFixture.enableInspections(inspection)
myFixture.configureByText(GROOVY_FILE_TYPE, "${DECLARATIONS} ${text}")
}
private getMessage(String text) {
def _ = Pattern.quote(_)
def (__, prefix, method, suffix) = (text =~ /^(?:(.*?)${_})?(.+?)(?:${_}(.*?))?$/)[0]
[prefix ?: '', method, suffix ?: '']
}
}