From f534949f192812bf2a01f1b473795c7a5fbe138d Mon Sep 17 00:00:00 2001 From: "Maxim.Medvedev" Date: Thu, 26 Jan 2012 13:34:27 +0400 Subject: [PATCH] primitive type parameters are not allowed in Groovy --- .../plugins/groovy/GroovyBundle.properties | 2 + .../groovy/annotator/GroovyAnnotator.java | 29 +++++++ .../GrReplacePrimitiveTypeWithWrapperFix.java | 82 +++++++++++++++++++ .../GroovyIntentionsBundle.properties | 2 + .../groovy/lang/GroovyHighlightingTest.groovy | 10 +++ 5 files changed, 125 insertions(+) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GrReplacePrimitiveTypeWithWrapperFix.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index 64a82a96e8d2..d74bd47847b8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -299,3 +299,5 @@ add.parentheses=Add parentheses add.parentheses.to.command.method.call=Add parentheses to command method call dollar.slash.strings.are.not.allowed.in.0=Dollar slashy strings are not allowed in Groovy {0} method.with.type.parameters.should.have.return.type=Method with type parameters should have return type +primitive.type.parameters.are.not.allowed=Primitive type parameters are not allowed +primitive.bound.types.are.not.allowed=Primitive bound types are not allowed diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 2ca3a97f1d02..f730ea5d9d91 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -657,6 +657,35 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { checkNamedArgs(listOrMap.getNamedArguments(), false); } + @Override + public void visitClassTypeElement(GrClassTypeElement typeElement) { + super.visitClassTypeElement(typeElement); + + final GrCodeReferenceElement ref = typeElement.getReferenceElement(); + final GrTypeArgumentList argList = ref.getTypeArgumentList(); + if (argList == null) return; + + final GrTypeElement[] elements = argList.getTypeArgumentElements(); + for (GrTypeElement element : elements) { + checkTypeArgForPrimitive(element, GroovyBundle.message("primitive.type.parameters.are.not.allowed")); + } + } + + private void checkTypeArgForPrimitive(@Nullable GrTypeElement element, String message) { + if (element == null || !(element.getType() instanceof PsiPrimitiveType)) return; + + myHolder. + createErrorAnnotation(element, message). + registerFix(new GrReplacePrimitiveTypeWithWrapperFix(element)); + } + + @Override + public void visitWildcardTypeArgument(GrWildcardTypeArgument wildcardTypeArgument) { + super.visitWildcardTypeArgument(wildcardTypeArgument); + + checkTypeArgForPrimitive(wildcardTypeArgument.getBoundTypeElement(), GroovyBundle.message("primitive.bound.types.are.not.allowed")); + } + private void highlightNamedArgs(GrNamedArgument[] namedArguments) { for (GrNamedArgument namedArgument : namedArguments) { final GrArgumentLabel label = namedArgument.getLabel(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GrReplacePrimitiveTypeWithWrapperFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GrReplacePrimitiveTypeWithWrapperFix.java new file mode 100644 index 000000000000..31e17f25a7de --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GrReplacePrimitiveTypeWithWrapperFix.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2012 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.annotator.intentions; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle; +import org.jetbrains.plugins.groovy.lang.GrReferenceAdjuster; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; + +/** + * @author Max Medvedev + */ +public class GrReplacePrimitiveTypeWithWrapperFix implements IntentionAction { + private static final Logger LOG = Logger.getInstance(GrReplacePrimitiveTypeWithWrapperFix.class); + + private final GrTypeElement myTypeElement; + private final String myBoxedName; + + public GrReplacePrimitiveTypeWithWrapperFix(GrTypeElement typeElement) { + LOG.assertTrue(typeElement.isValid()); + myTypeElement = typeElement; + + final PsiType type = typeElement.getType(); + LOG.assertTrue(type instanceof PsiPrimitiveType); + + myBoxedName = ((PsiPrimitiveType)type).getBoxedType(typeElement).getClassName(); + } + + @NotNull + @Override + public String getText() { + return GroovyIntentionsBundle.message("replace.with.wrapper", myBoxedName); + } + + @NotNull + @Override + public String getFamilyName() { + return GroovyIntentionsBundle.message("replace.primitive.type.with.wrapper"); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return myTypeElement.isValid() && myTypeElement.getType() instanceof PsiPrimitiveType; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiType type = myTypeElement.getType(); + if (!(type instanceof PsiPrimitiveType)) return; + + final PsiClassType boxed = ((PsiPrimitiveType)type).getBoxedType(myTypeElement); + final GrTypeElement newTypeElement = GroovyPsiElementFactory.getInstance(project).createTypeElement(boxed); + + final PsiElement replaced = myTypeElement.replace(newTypeElement); + GrReferenceAdjuster.shortenReferences(replaced); + } + + @Override + public boolean startInWriteAction() { + return true; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties index 97a40ccf621a..14e5bb9b7906 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties @@ -143,3 +143,5 @@ remove.unnecessary.semicolons.family.name=Remove unnecessary semicolons from sel no.unnecessary.semicolons.found=No unnecessary semicolons found add.return.type=Add return type add.return.type.to.method.declaration=Add return type to method declaration +replace.with.wrapper=Replace with {0} +replace.primitive.type.with.wrapper=Replace primitive type with wrapper diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy index 1e9f23e6a8dc..76bf926f58e9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy @@ -645,4 +645,14 @@ def result = new Foo().x''') myFixture.enableInspections(new ClashingGettersInspection()) myFixture.testHighlighting(true, false, false) } + + void testPrimitiveTypeParams() { + myFixture.configureByText('a.groovy', ''' +List<int> list = new ArrayList +Listdouble> l = new ArrayList() +List list2 + +''') + myFixture.testHighlighting(true, false, false) + } } \ No newline at end of file