@Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { super.visitReferenceElement(reference); if (referenceFound) { return; } final String text = reference.getText(); if (text.indexOf((int) '.') >= 0 || !name.equals(text)) { return; } final PsiElement element = reference.resolve(); if (!(element instanceof PsiClass) || element instanceof PsiTypeParameter) { return; } final PsiClass aClass = (PsiClass) element; final String testClassName = aClass.getName(); final String testClassQualifiedName = aClass.getQualifiedName(); if (testClassQualifiedName == null || testClassName == null || testClassQualifiedName.equals(fullyQualifiedName) || !testClassName.equals(name)) { return; } referenceFound = true; }
/** * The parameter <code>allowIndirect</code> determines if the method should look for indirect * annotations, i.e. annotations which have themselves been annotated by the supplied annotation * name. Currently, this only allows one level of indirection and returns an array of * [base-annotation, indirect annotation] * * <p>The <code>annotationName</code> parameter is a pair of the target annotation class' fully * qualified name as a String and as a Set. This is done for performance reasons because the Set * is required by the {@link com.intellij.codeInsight.AnnotationUtil} utility class and allows to * avoid unnecessary object constructions. */ public static PsiAnnotation[] getAnnotationsFromImpl( PsiModifierListOwner owner, Pair<String, ? extends Set<String>> annotationName, boolean allowIndirect, boolean inHierarchy) { final PsiAnnotation directAnnotation = inHierarchy ? AnnotationUtil.findAnnotationInHierarchy(owner, annotationName.second) : AnnotationUtil.findAnnotation(owner, annotationName.second); if (directAnnotation != null) { return new PsiAnnotation[] {directAnnotation}; } if (allowIndirect) { final PsiAnnotation[] annotations = getAnnotations(owner, inHierarchy); for (PsiAnnotation annotation : annotations) { PsiJavaCodeReferenceElement nameReference = annotation.getNameReferenceElement(); if (nameReference == null) continue; PsiElement resolved = nameReference.resolve(); if (resolved instanceof PsiClass) { final PsiAnnotation psiAnnotation = AnnotationUtil.findAnnotationInHierarchy( (PsiModifierListOwner) resolved, annotationName.second); if (psiAnnotation != null) { return new PsiAnnotation[] {psiAnnotation, annotation}; } } } } return PsiAnnotation.EMPTY_ARRAY; }
public static String checkTypeArguments(PsiTypeElement qualifier, PsiType psiType) { if (psiType instanceof PsiClassType) { final PsiJavaCodeReferenceElement referenceElement = qualifier.getInnermostComponentReferenceElement(); if (referenceElement != null) { PsiType[] typeParameters = referenceElement.getTypeParameters(); for (PsiType typeParameter : typeParameters) { if (typeParameter instanceof PsiWildcardType) { return "Unexpected wildcard"; } } } } return null; }
@Override public void removeRedundantImports(@NotNull final PsiJavaFile file) throws IncorrectOperationException { final Collection<PsiImportStatementBase> redundant = findRedundantImports(file); if (redundant == null) return; for (final PsiImportStatementBase importStatement : redundant) { final PsiJavaCodeReferenceElement ref = importStatement.getImportReference(); // Do not remove non-resolving refs if (ref == null || ref.resolve() == null) { continue; } importStatement.delete(); } }
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { if (referenceFound) { return; } super.visitReferenceElement(reference); if (reference.isQualified()) { return; } final PsiElement target = reference.resolve(); for (PsiMember member : members) { if (member.equals(target)) { referenceFound = true; return; } } }
/** * @param strict if strict is true this method checks if the conflicting class which is imported * is actually used in the file. If it isn't the on demand import can be overridden with an * exact import for the fqName without breaking stuff. */ private static boolean hasOnDemandImportConflict( @NotNull String fqName, @NotNull PsiJavaFile file, boolean strict) { final PsiImportList imports = file.getImportList(); if (imports == null) { return false; } final PsiImportStatement[] importStatements = imports.getImportStatements(); final String shortName = ClassUtil.extractClassName(fqName); final String packageName = ClassUtil.extractPackageName(fqName); for (final PsiImportStatement importStatement : importStatements) { if (!importStatement.isOnDemand()) { continue; } final PsiJavaCodeReferenceElement importReference = importStatement.getImportReference(); if (importReference == null) { continue; } final String packageText = importReference.getText(); if (packageText.equals(packageName)) { continue; } final PsiElement element = importReference.resolve(); if (element == null || !(element instanceof PsiPackage)) { continue; } final PsiPackage aPackage = (PsiPackage) element; final PsiClass[] classes = aPackage.getClasses(); for (final PsiClass aClass : classes) { final String className = aClass.getName(); if (!shortName.equals(className)) { continue; } if (!strict) { return true; } final String qualifiedClassName = aClass.getQualifiedName(); if (qualifiedClassName == null || fqName.equals(qualifiedClassName)) { continue; } return containsReferenceToConflictingClass(file, qualifiedClassName); } } return hasJavaLangImportConflict(fqName, file); }
@Nullable private static PsiImportStaticStatement findOnDemandImportStaticStatement( PsiImportList importList, String qualifierClass) { final PsiImportStaticStatement[] importStaticStatements = importList.getImportStaticStatements(); for (PsiImportStaticStatement importStaticStatement : importStaticStatements) { if (!importStaticStatement.isOnDemand()) { continue; } final PsiJavaCodeReferenceElement importReference = importStaticStatement.getImportReference(); if (importReference == null) { continue; } final String text = importReference.getText(); if (qualifierClass.equals(text)) { return importStaticStatement; } } return null; }
private static boolean hasExactImportStaticConflict( String qualifierClass, String memberName, PsiElement context) { final PsiFile file = context.getContainingFile(); if (!(file instanceof PsiJavaFile)) { return false; } final PsiJavaFile javaFile = (PsiJavaFile) file; final PsiImportList importList = javaFile.getImportList(); if (importList == null) { return false; } final PsiImportStaticStatement[] importStaticStatements = importList.getImportStaticStatements(); for (PsiImportStaticStatement importStaticStatement : importStaticStatements) { if (importStaticStatement.isOnDemand()) { continue; } final String name = importStaticStatement.getReferenceName(); if (!memberName.equals(name)) { continue; } final PsiJavaCodeReferenceElement importReference = importStaticStatement.getImportReference(); if (importReference == null) { continue; } final PsiElement qualifier = importReference.getQualifier(); if (qualifier == null) { continue; } final String qualifierText = qualifier.getText(); if (!qualifierClass.equals(qualifierText)) { return true; } } return false; }
static AllowedValues getAllowedValues( @NotNull PsiModifierListOwner element, PsiType type, Set<PsiClass> visited) { PsiAnnotation[] annotations = AnnotationUtil.getAllAnnotations(element, true, null); for (PsiAnnotation annotation : annotations) { AllowedValues values; if (type != null && MagicConstant.class.getName().equals(annotation.getQualifiedName())) { // PsiAnnotation magic = AnnotationUtil.findAnnotationInHierarchy(element, // Collections.singleton(MagicConstant.class.getName())); values = getAllowedValuesFromMagic(element, type, annotation); if (values != null) return values; } PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement(); PsiElement resolved = ref == null ? null : ref.resolve(); if (!(resolved instanceof PsiClass) || !((PsiClass) resolved).isAnnotationType()) continue; PsiClass aClass = (PsiClass) resolved; if (visited == null) visited = new THashSet<PsiClass>(); if (!visited.add(aClass)) continue; values = getAllowedValues(aClass, type, visited); if (values != null) return values; } return parseBeanInfo(element); }
public static int insertClassReference( PsiClass psiClass, PsiFile file, int startOffset, int endOffset) { final Project project = file.getProject(); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); documentManager.commitAllDocuments(); final PsiManager manager = file.getManager(); final Document document = FileDocumentManager.getInstance().getDocument(file.getViewProvider().getVirtualFile()); final PsiReference reference = file.findReferenceAt(startOffset); if (reference != null) { final PsiElement resolved = reference.resolve(); if (resolved instanceof PsiClass) { if (((PsiClass) resolved).getQualifiedName() == null || manager.areElementsEquivalent(psiClass, resolved)) { return endOffset; } } } String name = psiClass.getName(); if (name == null) { return endOffset; } assert document != null; document.replaceString(startOffset, endOffset, name); int newEndOffset = startOffset + name.length(); final RangeMarker toDelete = insertTemporary(newEndOffset, document, " "); documentManager.commitAllDocuments(); PsiElement element = file.findElementAt(startOffset); if (element instanceof PsiIdentifier) { PsiElement parent = element.getParent(); if (parent instanceof PsiJavaCodeReferenceElement && !((PsiJavaCodeReferenceElement) parent).isQualified() && !(parent.getParent() instanceof PsiPackageStatement)) { PsiJavaCodeReferenceElement ref = (PsiJavaCodeReferenceElement) parent; if (psiClass.isValid() && !psiClass.getManager().areElementsEquivalent(psiClass, resolveReference(ref))) { final boolean staticImport = ref instanceof PsiImportStaticReferenceElement; PsiElement newElement; try { newElement = staticImport ? ((PsiImportStaticReferenceElement) ref).bindToTargetClass(psiClass) : ref.bindToElement(psiClass); } catch (IncorrectOperationException e) { return endOffset; // can happen if fqn contains reserved words, for example } final RangeMarker rangeMarker = document.createRangeMarker(newElement.getTextRange()); documentManager.doPostponedOperationsAndUnblockDocument(document); documentManager.commitDocument(document); newElement = CodeInsightUtilCore.findElementInRange( file, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(), PsiJavaCodeReferenceElement.class, JavaLanguage.INSTANCE); rangeMarker.dispose(); if (newElement != null) { newEndOffset = newElement.getTextRange().getEndOffset(); if (!(newElement instanceof PsiReferenceExpression)) { PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement) newElement).getParameterList(); if (parameterList != null) { newEndOffset = parameterList.getTextRange().getStartOffset(); } } if (!staticImport && !psiClass .getManager() .areElementsEquivalent(psiClass, resolveReference((PsiReference) newElement)) && !PsiUtil.isInnerClass(psiClass)) { final String qName = psiClass.getQualifiedName(); if (qName != null) { document.replaceString( newElement.getTextRange().getStartOffset(), newEndOffset, qName); newEndOffset = newElement.getTextRange().getStartOffset() + qName.length(); } } } } } } if (toDelete.isValid()) { document.deleteString(toDelete.getStartOffset(), toDelete.getEndOffset()); } return newEndOffset; }
public static String checkMethodReferenceContext( PsiMethodReferenceExpression methodRef, PsiElement resolve, PsiType functionalInterfaceType) { final PsiClass containingClass = resolve instanceof PsiMethod ? ((PsiMethod) resolve).getContainingClass() : (PsiClass) resolve; final boolean isStaticSelector = isStaticallyReferenced(methodRef); final PsiElement qualifier = methodRef.getQualifier(); boolean isMethodStatic = false; boolean receiverReferenced = false; boolean isConstructor = true; if (resolve instanceof PsiMethod) { final PsiMethod method = (PsiMethod) resolve; isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC); isConstructor = method.isConstructor(); receiverReferenced = hasReceiver(methodRef, method, functionalInterfaceType); if (method.hasModifierProperty(PsiModifier.ABSTRACT) && qualifier instanceof PsiSuperExpression) { return "Abstract method '" + method.getName() + "' cannot be accessed directly"; } } if (!receiverReferenced && isStaticSelector && !isMethodStatic && !isConstructor) { return "Non-static method cannot be referenced from a static context"; } if (!receiverReferenced && !isStaticSelector && isMethodStatic) { return "Static method referenced through non-static qualifier"; } if (receiverReferenced && isStaticSelector && isMethodStatic && !isConstructor) { return "Static method referenced through receiver"; } if (isMethodStatic && isStaticSelector && qualifier instanceof PsiTypeElement) { final PsiJavaCodeReferenceElement referenceElement = PsiTreeUtil.getChildOfType(qualifier, PsiJavaCodeReferenceElement.class); if (referenceElement != null) { final PsiReferenceParameterList parameterList = referenceElement.getParameterList(); if (parameterList != null && parameterList.getTypeArguments().length > 0) { return "Parameterized qualifier on static method reference"; } } } if (isConstructor) { if (containingClass != null && PsiUtil.isInnerClass(containingClass) && containingClass.isPhysical()) { PsiClass outerClass = containingClass.getContainingClass(); if (outerClass != null && !InheritanceUtil.hasEnclosingInstanceInScope(outerClass, methodRef, true, false)) { return "An enclosing instance of type " + PsiFormatUtil.formatClass(outerClass, PsiFormatUtilBase.SHOW_NAME) + " is not in scope"; } } } return null; }
public static boolean isFreeFromTypeInferenceArgs( final PsiParameter[] methodParameters, final PsiLambdaExpression lambdaExpression, final PsiExpression expression, final PsiSubstitutor subst, final PsiType functionalInterfaceType, final PsiTypeParameter typeParam) { if (expression instanceof PsiCallExpression && ((PsiCallExpression) expression).getTypeArguments().length > 0) return true; if (expression instanceof PsiNewExpression) { final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression) expression).getClassOrAnonymousClassReference(); if (classReference != null) { final PsiReferenceParameterList parameterList = classReference.getParameterList(); if (parameterList != null) { final PsiTypeElement[] typeParameterElements = parameterList.getTypeParameterElements(); if (typeParameterElements.length > 0) { if (!(typeParameterElements[0].getType() instanceof PsiDiamondType)) { return true; } } } } } final PsiParameter[] lambdaParams = lambdaExpression.getParameterList().getParameters(); if (lambdaParams.length != methodParameters.length) return false; final boolean[] independent = {true}; final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(functionalInterfaceType); if (interfaceMethod == null) return false; final TypeParamsChecker paramsChecker = new TypeParamsChecker(lambdaExpression); for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) { subst.substitute(parameter.getType()).accept(paramsChecker); } paramsChecker.myUsedTypeParams.add(typeParam); expression.accept( new JavaRecursiveElementWalkingVisitor() { @Override public void visitConditionalExpression(PsiConditionalExpression expression) { final PsiExpression thenExpression = expression.getThenExpression(); if (thenExpression != null) { thenExpression.accept(this); } final PsiExpression elseExpression = expression.getElseExpression(); if (elseExpression != null) { elseExpression.accept(this); } } @Override public void visitReferenceExpression(PsiReferenceExpression expression) { super.visitReferenceExpression(expression); int usedParamIdx = -1; for (int i = 0; i < lambdaParams.length; i++) { PsiParameter param = lambdaParams[i]; if (expression.isReferenceTo(param)) { usedParamIdx = i; break; } } if (usedParamIdx > -1 && dependsOnTypeParams( subst.substitute(methodParameters[usedParamIdx].getType()), functionalInterfaceType, lambdaExpression, paramsChecker.myUsedTypeParams.toArray( new PsiTypeParameter[paramsChecker.myUsedTypeParams.size()]))) { independent[0] = false; } } }); return independent[0]; }