private static void registerReferenceFixes( GrReferenceExpression refExpr, HighlightInfo info, boolean compileStatic, final HighlightDisplayKey key) { PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr, compileStatic); if (targetClass == null) return; if (!compileStatic) { addDynamicAnnotation(info, refExpr, key); } if (targetClass.isWritable()) { QuickFixAction.registerQuickFixAction( info, new CreateFieldFromUsageFix(refExpr, targetClass), key); if (refExpr.getParent() instanceof GrCall && refExpr.getParent() instanceof GrExpression) { QuickFixAction.registerQuickFixAction( info, new CreateMethodFromUsageFix(refExpr, targetClass), key); } } if (!refExpr.isQualified()) { GrVariableDeclarationOwner owner = PsiTreeUtil.getParentOfType(refExpr, GrVariableDeclarationOwner.class); if (!(owner instanceof GroovyFileBase) || ((GroovyFileBase) owner).isScript()) { QuickFixAction.registerQuickFixAction( info, new CreateLocalVariableFromUsageFix(refExpr, owner), key); } if (PsiTreeUtil.getParentOfType(refExpr, GrMethod.class) != null) { QuickFixAction.registerQuickFixAction(info, new CreateParameterFromUsageFix(refExpr), key); } } }
public void visitReferenceExpression(GrReferenceExpression refExpr) { super.visitReferenceExpression(refExpr); if (myPolicy.isReferenceAccepted(refExpr)) { String name = refExpr.getReferenceName(); if (name == null) return; if (ControlFlowUtils.isIncOrDecOperand(refExpr)) { final InstructionImpl i = new ReadWriteVariableInstruction(name, refExpr, READ); addNodeAndCheckPending(i); addNode(new ReadWriteVariableInstruction(name, refExpr, WRITE)); } else { final int type = PsiUtil.isLValue(refExpr) ? WRITE : READ; addNodeAndCheckPending(new ReadWriteVariableInstruction(name, refExpr, type)); if (refExpr.getParent() instanceof GrArgumentList && refExpr.getParent().getParent() instanceof GrCall) { addNodeAndCheckPending(new ArgumentInstruction(refExpr)); } } } if (refExpr.isQualified() && !(refExpr.getParent() instanceof GrCall)) { visitCall(refExpr); } }
@Nullable private static HighlightInfo createAnnotationForRef( @NotNull GrReferenceExpression ref, boolean compileStatic, @NotNull String message) { PsiElement refNameElement = ref.getReferenceNameElement(); assert refNameElement != null; HighlightDisplayLevel displayLevel = getHighlightDisplayLevel(ref.getProject(), ref); if (compileStatic || displayLevel == HighlightDisplayLevel.ERROR) { return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) .range(refNameElement) .descriptionAndTooltip(message) .create(); } if (displayLevel == HighlightDisplayLevel.WARNING) { boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode(); HighlightInfoType infotype = isTestMode ? HighlightInfoType.WARNING : HighlightInfoType.INFORMATION; HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(infotype).range(refNameElement); builder.descriptionAndTooltip(message); return builder.needsUpdateOnTyping(false).textAttributes(UNRESOLVED_ACCESS).create(); } HighlightInfoType highlightInfoType = HighlightInfo.convertSeverity(displayLevel.getSeverity()); return HighlightInfo.newHighlightInfo(highlightInfoType) .range(refNameElement) .descriptionAndTooltip(message) .create(); }
public static boolean isClassReference(GrReferenceExpression ref) { GrExpression qualifier = ref.getQualifier(); return "class".equals(ref.getReferenceName()) && qualifier instanceof GrReferenceExpression && ((GrReferenceExpression) qualifier).resolve() instanceof PsiClass && !PsiUtil.isThisReference(qualifier); }
private static void addDynamicAnnotation( HighlightInfo info, GrReferenceExpression referenceExpression, HighlightDisplayKey key) { final PsiFile containingFile = referenceExpression.getContainingFile(); if (containingFile != null) { VirtualFile file = containingFile.getVirtualFile(); if (file == null) return; } else { return; } if (isCall(referenceExpression)) { PsiType[] argumentTypes = PsiUtil.getArgumentTypes(referenceExpression, false); if (argumentTypes != null) { QuickFixAction.registerQuickFixAction( info, referenceExpression.getTextRange(), new DynamicMethodFix(referenceExpression, argumentTypes), key); } } else { QuickFixAction.registerQuickFixAction( info, referenceExpression.getTextRange(), new DynamicPropertyFix(referenceExpression), key); } }
private static GrExpression genRefForGetter(GrMethodCall call, String accessorName) { String name = GroovyPropertyUtils.getPropertyNameByGetterName(accessorName, true); GrReferenceExpression refExpr = (GrReferenceExpression) call.getInvokedExpression(); String oldNameStr = refExpr.getReferenceNameElement().getText(); String newRefExpr = StringUtil.trimEnd(refExpr.getText(), oldNameStr) + name; final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(call.getProject()); return factory.createExpressionFromText(newRefExpr, call); }
private static boolean isPropertyAccessInStaticMethod(GrReferenceExpression referenceExpression) { if (referenceExpression.getParent() instanceof GrMethodCall || referenceExpression.getQualifier() != null) return false; GrMember context = PsiTreeUtil.getParentOfType( referenceExpression, GrMember.class, true, GrClosableBlock.class); return (context instanceof GrMethod || context instanceof GrClassInitializer) && context.hasModifierProperty(STATIC); }
@Nullable private static HighlightInfo checkRefInner(GrReferenceExpression ref) { PsiElement refNameElement = ref.getReferenceNameElement(); if (refNameElement == null) return null; boolean cannotBeDynamic = PsiUtil.isCompileStatic(ref) || isPropertyAccessInStaticMethod(ref); GroovyResolveResult resolveResult = getBestResolveResult(ref); if (resolveResult.getElement() != null) { if (!isInspectionEnabled(ref.getContainingFile(), ref.getProject())) return null; if (isStaticOk(resolveResult)) return null; String message = GroovyBundle.message("cannot.reference.non.static", ref.getReferenceName()); return createAnnotationForRef(ref, cannotBeDynamic, message); } if (ResolveUtil.isKeyOfMap(ref) || isClassReference(ref)) { return null; } if (!cannotBeDynamic) { if (!isInspectionEnabled(ref.getContainingFile(), ref.getProject())) return null; GrUnresolvedAccessInspection inspection = getInstance(ref.getContainingFile(), ref.getProject()); if (!inspection.myHighlightIfGroovyObjectOverridden && areGroovyObjectMethodsOverridden(ref)) return null; if (!inspection.myHighlightIfMissingMethodsDeclared && areMissingMethodsDeclared(ref)) return null; if (GroovySuppressableInspectionTool.isElementToolSuppressedIn(ref, SHORT_NAME)) return null; } if (cannotBeDynamic || shouldHighlightAsUnresolved(ref)) { HighlightInfo info = createAnnotationForRef( ref, cannotBeDynamic, GroovyBundle.message("cannot.resolve", ref.getReferenceName())); LOG.assertTrue(info != null); HighlightDisplayKey displayKey = HighlightDisplayKey.find(SHORT_NAME); if (ref.getParent() instanceof GrMethodCall) { registerStaticImportFix(ref, info, displayKey); } else { registerCreateClassByTypeFix(ref, info, displayKey); registerAddImportFixes(ref, info, displayKey); } registerReferenceFixes(ref, info, cannotBeDynamic, displayKey); UnresolvedReferenceQuickFixProvider.registerReferenceFixes( ref, new QuickFixActionRegistrarAdapter(info, displayKey)); OrderEntryFix.registerFixes(new QuickFixActionRegistrarAdapter(info, displayKey), ref); return info; } return null; }
@Override protected GrReferenceExpression bindWithQualifiedRef(@NotNull String qName) { final GrTypeArgumentList list = getTypeArgumentList(); final String typeArgs = (list != null) ? list.getText() : ""; final String text = qName + typeArgs; GrReferenceExpression qualifiedRef = GroovyPsiElementFactory.getInstance(getProject()).createReferenceExpressionFromText(text); getNode().getTreeParent().replaceChild(getNode(), qualifiedRef.getNode()); return qualifiedRef; }
private static void registerStaticImportFix( @NotNull GrReferenceExpression referenceExpression, @Nullable HighlightInfo info, @Nullable final HighlightDisplayKey key) { final String referenceName = referenceExpression.getReferenceName(); if (StringUtil.isEmpty(referenceName)) return; if (referenceExpression.getQualifier() != null) return; QuickFixAction.registerQuickFixAction( info, new GroovyStaticImportMethodFix((GrMethodCall) referenceExpression.getParent()), key); }
@Nullable public static GrExpression getRuntimeQualifier(GrReferenceExpression refExpr) { GrExpression qualifier = refExpr.getQualifierExpression(); if (qualifier != null) return qualifier; for (GrClosableBlock closure = PsiTreeUtil.getParentOfType(refExpr, GrClosableBlock.class); closure != null; closure = PsiTreeUtil.getParentOfType(closure, GrClosableBlock.class)) { PsiElement parent = closure.getParent(); if (parent instanceof GrArgumentList) parent = parent.getParent(); if (!(parent instanceof GrMethodCall)) continue; GrExpression funExpr = ((GrMethodCall) parent).getInvokedExpression(); if (!(funExpr instanceof GrReferenceExpression)) return funExpr; final PsiElement resolved = ((GrReferenceExpression) funExpr).resolve(); if (!(resolved instanceof PsiMethod)) return funExpr; if (resolved instanceof GrGdkMethod && isFromDGM((GrGdkMethod) resolved) && !GdkMethodUtil.isWithName(((GrGdkMethod) resolved).getStaticMethod().getName())) { continue; } qualifier = ((GrReferenceExpression) funExpr).getQualifierExpression(); if (qualifier != null) return qualifier; } return null; }
@NotNull public static GroovyResolveResult[] resolveNonQualifiedRefWithoutFlow( @NotNull GrReferenceExpression ref) { LOG.assertTrue(!ref.isQualified()); final String referenceName = ref.getReferenceName(); final ResolverProcessor processor = new PropertyResolverProcessor(referenceName, ref); ResolveUtil.treeWalkUp(ref, processor, false); final GroovyResolveResult[] candidates = processor.getCandidates(); if (candidates.length != 0) { return candidates; } return GroovyResolveResult.EMPTY_ARRAY; }
@Nullable private static GrAssignmentExpression genRefForSetter(GrMethodCall call, String accessorName) { String name = GroovyPropertyUtils.getPropertyNameBySetterName(accessorName); if (name == null) return null; GrExpression value = call.getExpressionArguments()[0]; GrReferenceExpression refExpr = (GrReferenceExpression) call.getInvokedExpression(); final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(call.getProject()); final GrAssignmentExpression assignment = (GrAssignmentExpression) factory.createStatementFromText("yyy = xxx", call); GrReferenceExpression lvalueRef = (GrReferenceExpression) assignment.getLValue(); lvalueRef.setQualifier(refExpr.getQualifier()); lvalueRef.handleElementRenameSimple(name); assignment.getRValue().replaceWithExpression(value, true); return assignment; }
private static boolean isSetterInvocation(GrMethodCall call) { GrExpression expr = call.getInvokedExpression(); if (!(expr instanceof GrReferenceExpression)) return false; GrReferenceExpression refExpr = (GrReferenceExpression) expr; PsiMethod method; if (call instanceof GrApplicationStatement) { PsiElement element = refExpr.resolve(); if (!(element instanceof PsiMethod) || !GroovyPropertyUtils.isSimplePropertySetter(((PsiMethod) element))) return false; method = (PsiMethod) element; } else { method = call.resolveMethod(); if (!GroovyPropertyUtils.isSimplePropertySetter(method)) return false; LOG.assertTrue(method != null); } if (!GroovyNamesUtil.isValidReference( GroovyPropertyUtils.getPropertyNameBySetterName(method.getName()), ((GrReferenceExpression) expr).getQualifier() != null, call.getProject())) { return false; } GrArgumentList args = call.getArgumentList(); if (args == null || args.getExpressionArguments().length != 1 || PsiImplUtil.hasNamedArguments(args)) { return false; } GrAssignmentExpression assignment = genRefForSetter(call, refExpr.getReferenceName()); if (assignment != null) { GrExpression value = assignment.getLValue(); if (value instanceof GrReferenceExpression && call.getManager() .areElementsEquivalent(((GrReferenceExpression) value).resolve(), method)) { return true; } } return false; }
public static int getPrecendence(GrExpression expression) { if (expression instanceof GrThisReferenceExpression || expression instanceof GrLiteral || expression instanceof GrSuperReferenceExpression) { return LITERAL_PRECEDENCE; } if (expression instanceof GrReferenceExpression) { final GrReferenceExpression referenceExpression = (GrReferenceExpression) expression; if (referenceExpression.getQualifierExpression() != null) { return METHOD_CALL_PRECEDENCE; } else { return LITERAL_PRECEDENCE; } } if (expression instanceof GrMethodCallExpression) { return METHOD_CALL_PRECEDENCE; } if (expression instanceof GrTypeCastExpression || expression instanceof GrNewExpression) { return TYPE_CAST_PRECEDENCE; } if (expression instanceof GrPostfixExpression) { return POSTFIX_PRECEDENCE; } if (expression instanceof GrUnaryExpression) { return PREFIX_PRECEDENCE; } if (expression instanceof GrBinaryExpression) { final GrBinaryExpression binaryExpression = (GrBinaryExpression) expression; final IElementType sign = binaryExpression.getOperationTokenType(); if (sign != null) return precedenceForBinaryOperator(sign); } if (expression instanceof GrConditionalExpression) { return CONDITIONAL_PRECEDENCE; } if (expression instanceof GrAssignmentExpression) { return ASSIGNMENT_PRECEDENCE; } if (expression instanceof GrParenthesizedExpression) { return PARENTHESIZED_PRECEDENCE; } return -1; }
private static boolean findClassByText(GrReferenceExpression ref) { final String text = ref.getText(); final int i = text.indexOf('<'); String className = i == -1 ? text : text.substring(0, i); PsiClass[] names = PsiShortNamesCache.getInstance(ref.getProject()) .getClassesByName(className, ref.getResolveScope()); if (names.length > 0) return true; PsiFile file = ref.getContainingFile(); if (file instanceof GroovyFile) { GrImportStatement[] imports = ((GroovyFile) file).getImportStatements(); for (GrImportStatement anImport : imports) { if (className.equals(anImport.getImportedName())) return true; } } return false; }
private static boolean shouldHighlightAsUnresolved( @NotNull GrReferenceExpression referenceExpression) { if (GrHighlightUtil.isDeclarationAssignment(referenceExpression)) return false; GrExpression qualifier = referenceExpression.getQualifier(); if (qualifier != null && qualifier.getType() == null && !isRefToPackage(qualifier)) return false; if (qualifier != null && referenceExpression.getDotTokenType() == GroovyTokenTypes.mMEMBER_POINTER && referenceExpression.multiResolve(false).length > 0) { return false; } if (!GroovyUnresolvedHighlightFilter.shouldHighlight(referenceExpression)) return false; CollectConsumer<PomTarget> consumer = new CollectConsumer<PomTarget>(); for (PomDeclarationSearcher searcher : PomDeclarationSearcher.EP_NAME.getExtensions()) { searcher.findDeclarationsAt(referenceExpression, 0, consumer); if (!consumer.getResult().isEmpty()) return false; } return true; }
private static boolean areGroovyObjectMethodsOverridden(GrReferenceExpression ref) { PsiType qualifierType = GrReferenceResolveUtil.getQualifierType(ref); if (!(qualifierType instanceof PsiClassType)) return false; PsiClass resolved = ((PsiClassType) qualifierType).resolve(); if (resolved == null) return false; PsiClass groovyObject = JavaPsiFacade.getInstance(ref.getProject()) .findClass(GroovyCommonClassNames.GROOVY_OBJECT, ref.getResolveScope()); if (groovyObject == null) return false; String methodName; if (ref.getParent() instanceof GrCall) { methodName = "invokeMethod"; } else if (PsiUtil.isLValue(ref)) { methodName = "setProperty"; } else { methodName = "getProperty"; } PsiMethod[] patternMethods = groovyObject.findMethodsByName(methodName, false); if (patternMethods.length != 1) return false; PsiMethod patternMethod = patternMethods[0]; PsiMethod found = resolved.findMethodBySignature(patternMethod, true); if (found == null) return false; PsiClass aClass = found.getContainingClass(); if (aClass == null) return false; String qname = aClass.getQualifiedName(); if (GroovyCommonClassNames.GROOVY_OBJECT.equals(qname)) return false; if (GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT.equals(qname)) return false; return true; }
private static GroovyResolveResult getBestResolveResult(GrReferenceExpression ref) { GroovyResolveResult[] results = ref.multiResolve(false); if (results.length == 0) return GroovyResolveResult.EMPTY_RESULT; if (results.length == 1) return results[0]; for (GroovyResolveResult result : results) { if (result.isAccessible() && result.isStaticsOK()) return result; } for (GroovyResolveResult result : results) { if (result.isStaticsOK()) return result; } return results[0]; }
private static boolean areMissingMethodsDeclared(GrReferenceExpression ref) { PsiType qualifierType = GrReferenceResolveUtil.getQualifierType(ref); if (!(qualifierType instanceof PsiClassType)) return false; PsiClass resolved = ((PsiClassType) qualifierType).resolve(); if (resolved == null) return false; if (ref.getParent() instanceof GrCall) { PsiMethod[] found = resolved.findMethodsByName("methodMissing", true); for (PsiMethod method : found) { if (MissingMethodAndPropertyUtil.isMethodMissing(method)) return true; } } else { PsiMethod[] found = resolved.findMethodsByName("propertyMissing", true); for (PsiMethod method : found) { if (MissingMethodAndPropertyUtil.isPropertyMissing(method)) return true; } } return false; }