mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-86459 Report Groovy 2.0 typing errors
This commit is contained in:
@@ -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) {
|
||||
|
||||
+9
-19
@@ -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);
|
||||
|
||||
+2
-1
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user