IDEA-86459 Report Groovy 2.0 typing errors

This commit is contained in:
Maxim.Medvedev
2012-05-30 16:11:56 +04:00
parent 27fca99c77
commit eb52dde764
5 changed files with 91 additions and 33 deletions
@@ -62,6 +62,7 @@ import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicMethodFi
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicPropertyFix;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
import org.jetbrains.plugins.groovy.debugger.fragments.GroovyCodeFragment;
import org.jetbrains.plugins.groovy.dsl.toplevel.AnnotatedContextFilter;
import org.jetbrains.plugins.groovy.extensions.GroovyUnresolvedHighlightFilter;
import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter;
import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil;
@@ -101,12 +102,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.*;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.TypeInferenceHelper;
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -324,6 +327,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
PsiElement resolved = resolveResult.getElement();
final PsiElement parent = referenceExpression.getParent();
if (resolved != null) {
if (resolved instanceof PsiMember) {
highlightMemberResolved(myHolder, referenceExpression, ((PsiMember)resolved));
@@ -337,7 +341,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
Annotation annotation = myHolder.createInfoAnnotation(referenceExpression,
GroovyBundle.message("cannot.reference.nonstatic",
referenceExpression.getReferenceName()));
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
annotation.setTextAttributes(isStaticallyCompiled(referenceExpression)?DefaultHighlighter.BAD_CHARACTER:DefaultHighlighter.UNRESOLVED_ACCESS);
}
}
}
@@ -377,8 +381,22 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
PsiElement refNameElement = referenceExpression.getReferenceNameElement();
PsiElement elt = refNameElement == null ? referenceExpression : refNameElement;
Annotation annotation = myHolder.createInfoAnnotation(elt, null);
final GrExpression qualifier = referenceExpression.getQualifierExpression();
Annotation annotation;
boolean compileStatic = isCompileStatic(referenceExpression);
if (compileStatic) {
annotation = myHolder.createInfoAnnotation(elt, GroovyBundle.message("cannot.resolve", referenceExpression.getReferenceName()));
annotation.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
}
else {
if (qualifier != null && qualifier.getType() == null) return;
annotation = myHolder.createInfoAnnotation(elt, null);
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
}
if (qualifier == null) {
if (parent instanceof GrMethodCall) {
registerStaticImportFix(referenceExpression, annotation);
@@ -388,20 +406,22 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
registerAddImportFixes(referenceExpression, annotation);
}
}
else {
if (qualifier.getType() == null) {
return;
}
}
registerReferenceFixes(referenceExpression, annotation);
registerReferenceFixes(referenceExpression, annotation, compileStatic);
UnresolvedReferenceQuickFixProvider.registerReferenceFixes(referenceExpression, new QuickFixActionRegistrarAdapter(annotation));
OrderEntryFix.registerFixes(new QuickFixActionRegistrarAdapter(annotation), referenceExpression);
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
}
}
private static boolean isCompileStatic(GrReferenceExpression referenceExpression) {
PsiMember containingMember = PsiTreeUtil.getParentOfType(referenceExpression, PsiMember.class);
return containingMember != null && GroovyPsiManager.getInstance(containingMember.getProject()).isCompileStatic(containingMember);
}
private static boolean isStaticallyCompiled(GrReferenceExpression referenceExpression) {
return AnnotatedContextFilter.findContextAnnotation(referenceExpression, GroovyCommonClassNames.GROOVY_TRANSFORM_COMPILE_STATIC)!=null;
}
private void highlightVariable(GrVariable variable, PsiElement toHighlight) {
Annotation annotation = myHolder.createInfoAnnotation(toHighlight, null);
boolean reassigned = isReassigned(variable);
@@ -1772,11 +1792,13 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
}
private static void registerReferenceFixes(GrReferenceExpression refExpr, Annotation annotation) {
PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr);
private static void registerReferenceFixes(GrReferenceExpression refExpr, Annotation annotation, boolean compileStatic) {
PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr, compileStatic);
if (targetClass == null) return;
addDynamicAnnotation(annotation, refExpr);
if (!compileStatic) {
addDynamicAnnotation(annotation, refExpr);
}
if (targetClass.isWritable()) {
if (!(targetClass instanceof GroovyScriptClass)) {
if (targetClass instanceof GrMemberOwner) {
@@ -26,7 +26,6 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.util.ArrayUtil;
import gnu.trove.THashSet;
@@ -34,13 +33,13 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ParamInfo;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicElementSettings;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceResolveUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -53,22 +52,13 @@ import java.util.*;
*/
public class QuickfixUtil {
@Nullable
public static PsiClass findTargetClass(GrReferenceExpression refExpr) {
final PsiClass psiClass;
if (refExpr.isQualified()) {
GrExpression qualifier = refExpr.getQualifierExpression();
PsiType type = qualifier.getType();
if (!(type instanceof PsiClassType)) return null;
psiClass = ((PsiClassType)type).resolve();
} else {
GroovyPsiElement context = PsiTreeUtil.getParentOfType(refExpr, GrTypeDefinition.class, GroovyFileBase.class);
if (context instanceof GrTypeDefinition) {
return (PsiClass)context;
} else if (context instanceof GroovyFileBase) return ((GroovyFileBase)context).getScriptClass();
return null;
public static PsiClass findTargetClass(GrReferenceExpression refExpr, boolean compileStatic) {
PsiType type = GrReferenceResolveUtil.getQualifierType(refExpr);
if (type == null && compileStatic) {
return GroovyPsiManager.getInstance(refExpr.getProject()).findClassWithCache(CommonClassNames.JAVA_LANG_OBJECT, refExpr.getResolveScope());
}
return psiClass;
if (!(type instanceof PsiClassType)) return null;
return ((PsiClassType)type).resolve();
}
public static boolean isStaticCall(GrReferenceExpression refExpr) {
@@ -184,7 +174,7 @@ public class QuickfixUtil {
public static DynamicElementSettings createSettings(GrReferenceExpression referenceExpression) {
DynamicElementSettings settings = new DynamicElementSettings();
final PsiClass containingClass = findTargetClass(referenceExpression);
final PsiClass containingClass = findTargetClass(referenceExpression, false);
assert containingClass != null;
String className = containingClass.getQualifiedName();
@@ -65,6 +65,7 @@ public class GroovyPsiManager {
private final ConcurrentMap<GroovyPsiElement, PsiType> myCalculatedTypes = new ConcurrentWeakHashMap<GroovyPsiElement, PsiType>();
private final ConcurrentMap<String, SoftReference<Map<GlobalSearchScope, PsiClass>>> myClassCache = new ConcurrentHashMap<String, SoftReference<Map<GlobalSearchScope, PsiClass>>>();
private final ConcurrentMap<PsiMember, Boolean> myCompileStatic = new ConcurrentHashMap<PsiMember, Boolean>();
private static final RecursionGuard ourGuard = RecursionManager.createGuard("groovyPsiManager");
@@ -92,6 +93,7 @@ public class GroovyPsiManager {
public void dropTypesCache() {
myCalculatedTypes.clear();
myCompileStatic.clear();
}
public static boolean isInheritorCached(@Nullable PsiClass aClass, @NotNull String baseClassName) {
@@ -122,6 +124,25 @@ public class GroovyPsiManager {
return JavaPsiFacade.getElementFactory(myProject).createTypeByFQClassName(fqName, resolveScope);
}
public boolean isCompileStatic(PsiMember member) {
Boolean aBoolean = myCompileStatic.get(member);
if (aBoolean == null) {
aBoolean = ConcurrencyUtil.cacheOrGet(myCompileStatic, member, isCompileStaticInner(member));
}
return aBoolean;
}
private boolean isCompileStaticInner(PsiMember member) {
PsiModifierList list = member.getModifierList();
if (list != null) {
PsiAnnotation annotation = list.findAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_COMPILE_STATIC);
if (annotation != null) return true;
}
PsiClass aClass = member.getContainingClass();
if (aClass != null) return isCompileStatic(aClass);
return false;
}
@Nullable
public PsiClass findClassWithCache(String fqName, GlobalSearchScope resolveScope) {
SoftReference<Map<GlobalSearchScope, PsiClass>> reference = myClassCache.get(fqName);
@@ -50,7 +50,8 @@ public final class GroovyCommonClassNames {
@NonNls public static final String GROOVY_LANG_USE = "groovy.lang.Use";
@NonNls public static final String GROOVY_LANG_MIXIN = "groovy.lang.Mixin";
@NonNls public static final String GROOVY_UTIL_TEST_CASE = "groovy.util.GroovyTestCase";
public static final String GROOVY_LANG_SINGLETON = "groovy.lang.Singleton";
@NonNls public static final String GROOVY_LANG_SINGLETON = "groovy.lang.Singleton";
@NonNls public static final String GROOVY_TRANSFORM_COMPILE_STATIC = "groovy.transform.CompileStatic";
private GroovyCommonClassNames() {
@@ -1009,4 +1009,28 @@ use(Ca) {
''', GroovyAssignabilityCheckInspection)
}
void testCompileStatic() {
myFixture.addClass('''\
package groovy.transform;
public @interface CompileStatic {
}''')
myFixture.configureByText('_.groovy', '''\
<info descr="null">import</info> <info descr="null">groovy.transform.CompileStatic</info>
<info descr="null">class</info> <info descr="null">A</info> {
<info descr="null">def</info> <info descr="null">foo</info>() {
<info descr="null">print</info> <info descr="null">abc</info>
}
<info descr="null">@CompileStatic</info>
<info descr="null">def</info> <info descr="null">bar</info>() {
<info descr="null">print</info> <info descr="Cannot resolve symbol 'abc'">abc</info>
}
}
''')
myFixture.testHighlighting(true, true, true)
}
}