private static void qualify(PsiMember member, PsiElement renamed, String name) { if (!(renamed instanceof GrReferenceExpression)) return; final PsiClass clazz = member.getContainingClass(); if (clazz == null) return; final GrReferenceExpression refExpr = (GrReferenceExpression) renamed; final PsiElement replaced; if (member.hasModifierProperty(GrModifier.STATIC)) { final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject()) .createReferenceExpressionFromText(clazz.getQualifiedName() + "." + name); replaced = refExpr.replace(newRefExpr); } else { final PsiClass containingClass = PsiTreeUtil.getParentOfType(renamed, PsiClass.class); if (member.getManager().areElementsEquivalent(containingClass, clazz)) { final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject()) .createReferenceExpressionFromText("this." + name); replaced = refExpr.replace(newRefExpr); } else { final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject()) .createReferenceExpressionFromText(clazz.getQualifiedName() + ".this." + name); replaced = refExpr.replace(newRefExpr); } } PsiUtil.shortenReferences((GroovyPsiElement) replaced); }
protected boolean isAccessible(final PsiElement element) { if (element instanceof PsiMember) { final PsiMember member = (PsiMember) element; return JavaResolveUtil.isAccessible( member, member.getContainingClass(), member.getModifierList(), this, null, null); } return true; }
@Nullable public static PsiField findPropertyFieldByMember(final PsiMember psiMember) { if (psiMember instanceof PsiField) { return (PsiField) psiMember; } else if (psiMember instanceof PsiMethod) { final PsiMethod psiMethod = (PsiMethod) psiMember; final PsiType returnType = psiMethod.getReturnType(); if (returnType == null) return null; final PsiCodeBlock body = psiMethod.getBody(); final PsiStatement[] statements = body == null ? null : body.getStatements(); final PsiStatement statement = statements == null || statements.length != 1 ? null : statements[0]; final PsiElement target; if (PsiType.VOID.equals(returnType)) { final PsiExpression expression = statement instanceof PsiExpressionStatement ? ((PsiExpressionStatement) statement).getExpression() : null; target = expression instanceof PsiAssignmentExpression ? ((PsiAssignmentExpression) expression).getLExpression() : null; } else { target = statement instanceof PsiReturnStatement ? ((PsiReturnStatement) statement).getReturnValue() : null; } final PsiElement resolved = target instanceof PsiReferenceExpression ? ((PsiReferenceExpression) target).resolve() : null; if (resolved instanceof PsiField) { final PsiField field = (PsiField) resolved; if (psiMember.getContainingClass() == field.getContainingClass() || psiMember.getContainingClass().isInheritor(field.getContainingClass(), true)) return field; } } return null; }
@Nullable public static String getMemberQualifiedName(PsiMember member) { if (member instanceof PsiClass) { return ((PsiClass) member).getQualifiedName(); } PsiClass containingClass = member.getContainingClass(); if (containingClass == null) return null; String className = containingClass.getQualifiedName(); if (className == null) return null; return className + "." + member.getName(); }
private static boolean inLambdaInsideClassInitialization( @Nullable PsiClass containingClass, PsiClass aClass) { PsiMember member = aClass; while (member != null) { if (member.getContainingClass() == containingClass) { return member instanceof PsiField || member instanceof PsiMethod && ((PsiMethod) member).isConstructor() || member instanceof PsiClassInitializer; } member = PsiTreeUtil.getParentOfType(member, PsiMember.class, true); } return false; }
private static boolean isSameField( @NotNull PsiMember enclosingCtrOrInitializer, @NotNull PsiField field, @NotNull PsiReferenceExpression reference, @NotNull PsiFile containingFile) { if (!containingFile .getManager() .areElementsEquivalent( enclosingCtrOrInitializer.getContainingClass(), field.getContainingClass())) return false; PsiExpression qualifierExpression = reference.getQualifierExpression(); return qualifierExpression == null || qualifierExpression instanceof PsiThisExpression; }
private static void shortenWithStaticImports( PsiElement affectedElement, int startOffset, int endOffset) { final int elementOffset = affectedElement.getTextOffset(); final int finalStartOffset = startOffset + elementOffset; final int finalEndOffset = endOffset + elementOffset; final List<PsiReferenceExpression> references = new ArrayList<PsiReferenceExpression>(); final JavaRecursiveElementVisitor collector = new JavaRecursiveElementVisitor() { @Override public void visitReferenceExpression(PsiReferenceExpression expression) { final int offset = expression.getTextOffset(); if (offset > finalEndOffset) { return; } super.visitReferenceExpression(expression); if (offset + expression.getTextLength() < finalStartOffset) if (expression.getQualifierExpression() == null) { return; } references.add(expression); } }; affectedElement.accept(collector); for (PsiReferenceExpression expression : references) { final PsiElement target = expression.resolve(); if (!(target instanceof PsiMember)) { continue; } final PsiMember member = (PsiMember) target; final PsiClass containingClass = member.getContainingClass(); if (containingClass == null) { continue; } final String className = containingClass.getQualifiedName(); if (className == null) { continue; } final String name = member.getName(); if (name == null) { continue; } if (ImportUtils.addStaticImport(className, name, expression)) { final PsiExpression qualifierExpression = expression.getQualifierExpression(); if (qualifierExpression != null) { qualifierExpression.delete(); } } } }
public static PsiReferenceExpression qualifyReference( PsiReferenceExpression referenceExpression, final PsiMember member, @Nullable final PsiClass qualifyingClass) throws IncorrectOperationException { PsiManager manager = referenceExpression.getManager(); PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(referenceExpression, PsiMethodCallExpression.class, true); while ((methodCallExpression) != null) { if (HighlightUtil.isSuperOrThisMethodCall(methodCallExpression)) { return referenceExpression; } methodCallExpression = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethodCallExpression.class, true); } PsiReferenceExpression expressionFromText; final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); if (qualifyingClass == null) { PsiClass parentClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class); final PsiClass containingClass = member.getContainingClass(); if (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { while (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { parentClass = PsiTreeUtil.getParentOfType(parentClass, PsiClass.class, true); } LOG.assertTrue(parentClass != null); expressionFromText = (PsiReferenceExpression) factory.createExpressionFromText("A.this." + member.getName(), null); ((PsiThisExpression) expressionFromText.getQualifierExpression()) .getQualifier() .replace(factory.createClassReferenceElement(parentClass)); } else { expressionFromText = (PsiReferenceExpression) factory.createExpressionFromText("this." + member.getName(), null); } } else { expressionFromText = (PsiReferenceExpression) factory.createExpressionFromText("A." + member.getName(), null); expressionFromText.setQualifierExpression(factory.createReferenceExpression(qualifyingClass)); } CodeStyleManager codeStyleManager = manager.getCodeStyleManager(); expressionFromText = (PsiReferenceExpression) codeStyleManager.reformat(expressionFromText); return (PsiReferenceExpression) referenceExpression.replace(expressionFromText); }
@NotNull public static SearchScope getMemberUseScope(@NotNull PsiMember member) { PsiFile file = member.getContainingFile(); PsiElement topElement = file == null ? member : file; Project project = topElement.getProject(); final GlobalSearchScope maximalUseScope = ResolveScopeManager.getInstance(project).getUseScope(topElement); if (isInServerPage(file)) return maximalUseScope; PsiClass aClass = member.getContainingClass(); if (aClass instanceof PsiAnonymousClass && !(aClass instanceof PsiEnumConstantInitializer && member instanceof PsiMethod && member.hasModifierProperty(PsiModifier.PUBLIC) && ((PsiMethod) member).findSuperMethods().length > 0)) { // member from anonymous class can be called from outside the class PsiElement methodCallExpr = PsiUtil.isLanguageLevel8OrHigher(aClass) ? PsiTreeUtil.getTopmostParentOfType(aClass, PsiStatement.class) : PsiTreeUtil.getParentOfType(aClass, PsiMethodCallExpression.class); return new LocalSearchScope(methodCallExpr != null ? methodCallExpr : aClass); } PsiModifierList modifierList = member.getModifierList(); int accessLevel = modifierList == null ? PsiUtil.ACCESS_LEVEL_PUBLIC : PsiUtil.getAccessLevel(modifierList); if (accessLevel == PsiUtil.ACCESS_LEVEL_PUBLIC || accessLevel == PsiUtil.ACCESS_LEVEL_PROTECTED) { return maximalUseScope; // class use scope doesn't matter, since another very visible class // can inherit from aClass } if (accessLevel == PsiUtil.ACCESS_LEVEL_PRIVATE) { PsiClass topClass = PsiUtil.getTopLevelClass(member); return topClass != null ? new LocalSearchScope(topClass) : file == null ? maximalUseScope : new LocalSearchScope(file); } if (file instanceof PsiJavaFile) { PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(((PsiJavaFile) file).getPackageName()); if (aPackage != null) { SearchScope scope = PackageScope.packageScope(aPackage, false); return scope.intersectWith(maximalUseScope); } } return maximalUseScope; }
protected void visitClassMemberReferenceElement( PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { if (classMember.hasModifierProperty(PsiModifier.STATIC)) { if (!myMembersToMove.contains(classMember) && RefactoringHierarchyUtil.isMemberBetween( myTargetSuperClass, mySourceClass, classMember)) { myReferences.add(classMemberReference); myReferees.add(classMember); myRefereeClasses.add(classMember.getContainingClass()); } else if (myMembersToMove.contains(classMember) || myMembersAfterMove.contains(classMember)) { myReferences.add(classMemberReference); myReferees.add(classMember); myRefereeClasses.add(myTargetSuperClass); } } }
public static boolean isStaticallyImported( @NotNull PsiMember member, @NotNull PsiElement context) { final PsiClass memberClass = member.getContainingClass(); if (memberClass == null) { return false; } final PsiClass containingClass = PsiTreeUtil.getParentOfType(context, PsiClass.class); if (InheritanceUtil.isInheritorOrSelf(containingClass, memberClass, true)) { return false; } final PsiFile psiFile = context.getContainingFile(); if (!(psiFile instanceof PsiJavaFile)) { return false; } final PsiJavaFile javaFile = (PsiJavaFile) psiFile; final PsiImportList importList = javaFile.getImportList(); if (importList == null) { return false; } final String memberName = member.getName(); if (memberName == null) { return false; } final PsiImportStatementBase existingImportStatement = importList.findSingleImportStatement(memberName); if (existingImportStatement instanceof PsiImportStaticStatement) { final PsiClass importClass = ((PsiImportStaticStatement) existingImportStatement).resolveTargetClass(); if (InheritanceUtil.isInheritorOrSelf(importClass, memberClass, true)) { return true; } } final String memberClassName = memberClass.getQualifiedName(); if (memberClassName == null) { return false; } final PsiImportStaticStatement onDemandImportStatement = findOnDemandImportStaticStatement(importList, memberClassName); if (onDemandImportStatement != null) { if (!hasOnDemandImportStaticConflict(memberClassName, memberName, context)) { return true; } } return false; }
public static boolean isInExcludedPackage( @NotNull final PsiMember member, boolean allowInstanceInnerClasses) { final String name = PsiUtil.getMemberQualifiedName(member); if (name == null) return false; if (!member.hasModifierProperty(PsiModifier.STATIC)) { if (member instanceof PsiMethod || member instanceof PsiField) { return false; } if (allowInstanceInnerClasses && member instanceof PsiClass && member.getContainingClass() != null) { return false; } } return ProjectCodeInsightSettings.getSettings(member.getProject()).isExcluded(name); }
public static Set<String> getAllLookupStrings(@NotNull PsiMember member) { Set<String> allLookupStrings = ContainerUtil.newLinkedHashSet(); String name = member.getName(); allLookupStrings.add(name); PsiClass containingClass = member.getContainingClass(); while (containingClass != null) { final String className = containingClass.getName(); if (className == null) { break; } name = className + "." + name; allLookupStrings.add(name); final PsiElement parent = containingClass.getParent(); if (!(parent instanceof PsiClass)) { break; } containingClass = (PsiClass) parent; } return allLookupStrings; }
@Override protected void visitClassMemberReferenceElement( PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { if (classMember != null && !willBeMoved(classMember, myMovedMembers)) { final PsiClass containingClass = classMember.getContainingClass(); if (containingClass != null) { if (!PsiUtil.isAccessibleFromPackage(classMember, myTargetPackage)) { if (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { myConflicts.putValue( myMember, RefactoringUIUtil.getDescription(classMember, true) + " won't be accessible"); } else if (classMember.hasModifierProperty(PsiModifier.PROTECTED) && !mySubClass.isInheritor(containingClass, true)) { myConflicts.putValue( myMember, RefactoringUIUtil.getDescription(classMember, true) + " won't be accessible"); } } } } }
public GrReferenceExpression bindToElementViaStaticImport(@NotNull PsiMember member) { if (getQualifier() != null) { throw new IncorrectOperationException("Reference has qualifier"); } if (StringUtil.isEmpty(getReferenceName())) { throw new IncorrectOperationException("Reference has empty name"); } PsiClass containingClass = member.getContainingClass(); if (containingClass == null) { throw new IncorrectOperationException("Member has no containing class"); } final PsiFile file = getContainingFile(); if (file instanceof GroovyFile) { GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(getProject()); String text = "import static " + containingClass.getQualifiedName() + "." + member.getName(); final GrImportStatement statement = factory.createImportStatementFromText(text); ((GroovyFile) file).addImport(statement); } return this; }
@NotNull public static SearchScope getMemberUseScope(@NotNull PsiMember member) { final GlobalSearchScope maximalUseScope = ResolveScopeManager.getElementUseScope(member); PsiFile file = member.getContainingFile(); if (isInServerPage(file)) return maximalUseScope; PsiClass aClass = member.getContainingClass(); if (aClass instanceof PsiAnonymousClass) { // member from anonymous class can be called from outside the class PsiElement methodCallExpr = PsiTreeUtil.getParentOfType(aClass, PsiMethodCallExpression.class); return new LocalSearchScope(methodCallExpr != null ? methodCallExpr : aClass); } if (member.hasModifierProperty(PsiModifier.PUBLIC)) { return maximalUseScope; // class use scope doesn't matter, since another very visible class // can inherit from aClass } else if (member.hasModifierProperty(PsiModifier.PROTECTED)) { return maximalUseScope; // class use scope doesn't matter, since another very visible class // can inherit from aClass } else if (member.hasModifierProperty(PsiModifier.PRIVATE)) { PsiClass topClass = PsiUtil.getTopLevelClass(member); return topClass != null ? new LocalSearchScope(topClass) : new LocalSearchScope(file); } else { if (file instanceof PsiJavaFile) { PsiPackage aPackage = JavaPsiFacade.getInstance(member.getProject()) .findPackage(((PsiJavaFile) file).getPackageName()); if (aPackage != null) { SearchScope scope = PackageScope.packageScope(aPackage, false); scope = scope.intersectWith(maximalUseScope); return scope; } } return maximalUseScope; } }
public static GrReferenceExpression qualifyReference( GrReferenceExpression referenceExpression, final PsiMember member, @Nullable final PsiClass qualifyingClass) throws IncorrectOperationException { PsiManager manager = referenceExpression.getManager(); GrReferenceExpression expressionFromText; final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(referenceExpression.getProject()); if (qualifyingClass == null) { PsiClass parentClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class); final PsiClass containingClass = member.getContainingClass(); if (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { while (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { parentClass = PsiTreeUtil.getParentOfType(parentClass, PsiClass.class, true); } LOG.assertTrue(parentClass != null); expressionFromText = factory.createReferenceExpressionFromText("A.this." + member.getName()); //noinspection ConstantConditions ((GrReferenceExpression) expressionFromText.getQualifier()) .getQualifier() .replace(factory.createReferenceElementForClass(parentClass)); } else { expressionFromText = (GrReferenceExpression) factory.createExpressionFromText("this." + member.getName()); } } else { expressionFromText = (GrReferenceExpression) factory.createExpressionFromText("A." + member.getName()); expressionFromText.setQualifier(factory.createReferenceElementForClass(qualifyingClass)); } CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); expressionFromText = (GrReferenceExpression) codeStyleManager.reformat(expressionFromText); return (GrReferenceExpression) referenceExpression.replace(expressionFromText); }
private static void checkSuperclassMembers( PsiClass superClass, MemberInfoBase<? extends PsiMember>[] infos, MultiMap<PsiElement, String> conflictsList) { for (MemberInfoBase<? extends PsiMember> info : infos) { PsiMember member = info.getMember(); boolean isConflict = false; if (member instanceof PsiField) { String name = member.getName(); isConflict = superClass.findFieldByName(name, false) != null; } else if (member instanceof PsiMethod) { PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor( superClass, member.getContainingClass(), PsiSubstitutor.EMPTY); MethodSignature signature = ((PsiMethod) member).getSignature(superSubstitutor); final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(superClass, signature, false); isConflict = superClassMethod != null; } if (isConflict) { String message = RefactoringBundle.message( "0.already.contains.a.1", RefactoringUIUtil.getDescription(superClass, false), RefactoringUIUtil.getDescription(member, false)); message = CommonRefactoringUtil.capitalize(message); conflictsList.putValue(superClass, message); } if (member instanceof PsiMethod) { final PsiMethod method = (PsiMethod) member; final PsiModifierList modifierList = method.getModifierList(); if (!modifierList.hasModifierProperty(PsiModifier.PRIVATE)) { for (PsiClass subClass : ClassInheritorsSearch.search(superClass)) { if (method.getContainingClass() != subClass) { MethodSignature signature = ((PsiMethod) member) .getSignature( TypeConversionUtil.getSuperClassSubstitutor( superClass, subClass, PsiSubstitutor.EMPTY)); final PsiMethod wouldBeOverriden = MethodSignatureUtil.findMethodBySignature(subClass, signature, false); if (wouldBeOverriden != null && VisibilityUtil.compare( VisibilityUtil.getVisibilityModifier(wouldBeOverriden.getModifierList()), VisibilityUtil.getVisibilityModifier(modifierList)) > 0) { conflictsList.putValue( wouldBeOverriden, CommonRefactoringUtil.capitalize( RefactoringUIUtil.getDescription(method, true) + " in super class would clash with local method from " + RefactoringUIUtil.getDescription(subClass, true))); } } } } } } }
@Override public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { if (!LambdaUtil.isFunctionalType(myT)) { return false; } final PsiType groundTargetType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(myT); final PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(groundTargetType); final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(classResolveResult); if (interfaceMethod == null) { return false; } final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, classResolveResult); final PsiParameter[] targetParameters = interfaceMethod.getParameterList().getParameters(); final PsiType interfaceMethodReturnType = interfaceMethod.getReturnType(); final PsiType returnType = substitutor.substitute(interfaceMethodReturnType); final PsiType[] typeParameters = myExpression.getTypeParameters(); final PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult = PsiMethodReferenceUtil.getQualifierResolveResult(myExpression); if (!myExpression.isExact()) { for (PsiParameter parameter : targetParameters) { if (!session.isProperType(substitutor.substitute(parameter.getType()))) { return false; } } } else { final PsiMember applicableMember = myExpression.getPotentiallyApplicableMember(); LOG.assertTrue(applicableMember != null); final PsiClass applicableMemberContainingClass = applicableMember.getContainingClass(); final PsiClass containingClass = qualifierResolveResult.getContainingClass(); PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor(); psiSubstitutor = applicableMemberContainingClass == null || containingClass == null || myExpression.isConstructor() ? psiSubstitutor : TypeConversionUtil.getSuperClassSubstitutor( applicableMemberContainingClass, containingClass, psiSubstitutor); PsiType applicableMethodReturnType = applicableMember instanceof PsiMethod ? ((PsiMethod) applicableMember).getReturnType() : null; int idx = 0; for (PsiTypeParameter param : ((PsiTypeParameterListOwner) applicableMember).getTypeParameters()) { if (idx < typeParameters.length) { psiSubstitutor = psiSubstitutor.put(param, typeParameters[idx++]); } } final PsiParameter[] parameters = applicableMember instanceof PsiMethod ? ((PsiMethod) applicableMember).getParameterList().getParameters() : PsiParameter.EMPTY_ARRAY; if (targetParameters.length == parameters.length + 1) { specialCase(session, constraints, substitutor, targetParameters, true); for (int i = 1; i < targetParameters.length; i++) { constraints.add( new TypeCompatibilityConstraint( session.substituteWithInferenceVariables( psiSubstitutor.substitute(parameters[i - 1].getType())), substitutor.substitute(targetParameters[i].getType()))); } } else if (targetParameters.length == parameters.length) { for (int i = 0; i < targetParameters.length; i++) { constraints.add( new TypeCompatibilityConstraint( session.substituteWithInferenceVariables( psiSubstitutor.substitute(parameters[i].getType())), substitutor.substitute(targetParameters[i].getType()))); } } else { return false; } if (returnType != PsiType.VOID && returnType != null) { if (applicableMethodReturnType == PsiType.VOID) { return false; } if (applicableMethodReturnType != null) { constraints.add( new TypeCompatibilityConstraint( returnType, session.substituteWithInferenceVariables( psiSubstitutor.substitute(applicableMethodReturnType)))); } else if (applicableMember instanceof PsiClass || applicableMember instanceof PsiMethod && ((PsiMethod) applicableMember).isConstructor()) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(applicableMember.getProject()); if (containingClass != null) { final PsiType classType = session.substituteWithInferenceVariables( elementFactory.createType(containingClass, psiSubstitutor)); constraints.add(new TypeCompatibilityConstraint(returnType, classType)); } } } return true; } final Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap(); final PsiType added = map.put(myExpression, session.startWithFreshVars(groundTargetType)); final JavaResolveResult resolve; try { resolve = myExpression.advancedResolve(true); } finally { if (added == null) { map.remove(myExpression); } } final PsiElement element = resolve.getElement(); if (element == null) { return false; } if (PsiType.VOID.equals(returnType) || returnType == null) { return true; } if (element instanceof PsiMethod) { final PsiMethod method = (PsiMethod) element; final PsiType referencedMethodReturnType; final PsiClass containingClass = method.getContainingClass(); LOG.assertTrue(containingClass != null, method); PsiClass qContainingClass = qualifierResolveResult.getContainingClass(); PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor(); if (qContainingClass != null) { if (PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) { psiSubstitutor = PsiSubstitutor.EMPTY; } if (qContainingClass.isInheritor(containingClass, true)) { psiSubstitutor = TypeConversionUtil.getClassSubstitutor( containingClass, qContainingClass, PsiSubstitutor.EMPTY); LOG.assertTrue(psiSubstitutor != null); } } if (method.isConstructor()) { referencedMethodReturnType = JavaPsiFacade.getElementFactory(method.getProject()) .createType(containingClass, PsiSubstitutor.EMPTY); } else { referencedMethodReturnType = method.getReturnType(); } LOG.assertTrue(referencedMethodReturnType != null, method); if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) || PsiUtil.getEnclosingStaticElement(myExpression, containingClass) != null) { session.initBounds(myExpression, containingClass.getTypeParameters()); } session.initBounds(myExpression, method.getTypeParameters()); // if i) the method reference elides NonWildTypeArguments, // ii) the compile-time declaration is a generic method, and // iii) the return type of the compile-time declaration mentions at least one of the method's // type parameters; if (typeParameters.length == 0 && method.getTypeParameters().length > 0) { final PsiClass interfaceClass = classResolveResult.getElement(); LOG.assertTrue(interfaceClass != null); if (PsiPolyExpressionUtil.mentionsTypeParameters( referencedMethodReturnType, ContainerUtil.newHashSet(method.getTypeParameters()))) { // the constraint reduces to the bound set B3 which would be used to determine the method // reference's invocation type // when targeting the return type of the function type, as defined in 18.5.2. session.collectApplicabilityConstraints( myExpression, ((MethodCandidateInfo) resolve), groundTargetType); session.registerReturnTypeConstraints(referencedMethodReturnType, returnType); return true; } } if (PsiType.VOID.equals(referencedMethodReturnType)) { return false; } int idx = 0; for (PsiTypeParameter param : method.getTypeParameters()) { if (idx < typeParameters.length) { psiSubstitutor = psiSubstitutor.put(param, typeParameters[idx++]); } } final PsiParameter[] parameters = method.getParameterList().getParameters(); if (targetParameters.length == parameters.length + 1 && !method.isVarArgs() && PsiPolyExpressionUtil.mentionsTypeParameters( referencedMethodReturnType, ContainerUtil.newHashSet( containingClass.getTypeParameters()))) { // todo specification bug? specialCase(session, constraints, substitutor, targetParameters, false); } constraints.add( new TypeCompatibilityConstraint( returnType, session.substituteWithInferenceVariables( psiSubstitutor.substitute(referencedMethodReturnType)))); } return true; }
@Nullable public static HighlightInfo checkFinalVariableMightAlreadyHaveBeenAssignedTo( @NotNull PsiVariable variable, @NotNull PsiReferenceExpression expression, @NotNull Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> finalVarProblems) { if (!PsiUtil.isAccessedForWriting(expression)) return null; final PsiElement scope = variable instanceof PsiField ? variable.getParent() : variable.getParent() == null ? null : variable.getParent().getParent(); PsiElement codeBlock = PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope); if (codeBlock == null) return null; Collection<ControlFlowUtil.VariableInfo> codeBlockProblems = getFinalVariableProblemsInBlock(finalVarProblems, codeBlock); boolean alreadyAssigned = false; for (ControlFlowUtil.VariableInfo variableInfo : codeBlockProblems) { if (variableInfo.expression == expression) { alreadyAssigned = true; break; } } if (!alreadyAssigned) { if (!(variable instanceof PsiField)) return null; final PsiField field = (PsiField) variable; final PsiClass aClass = field.getContainingClass(); if (aClass == null) return null; // field can get assigned in other field initializers final PsiField[] fields = aClass.getFields(); boolean isFieldStatic = field.hasModifierProperty(PsiModifier.STATIC); for (PsiField psiField : fields) { PsiExpression initializer = psiField.getInitializer(); if (psiField != field && psiField.hasModifierProperty(PsiModifier.STATIC) == isFieldStatic && initializer != null && initializer != codeBlock && !variableDefinitelyNotAssignedIn(field, initializer)) { alreadyAssigned = true; break; } } if (!alreadyAssigned) { // field can get assigned in class initializers final PsiMember enclosingConstructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expression); if (enclosingConstructorOrInitializer == null || !aClass .getManager() .areElementsEquivalent( enclosingConstructorOrInitializer.getContainingClass(), aClass)) { return null; } final PsiClassInitializer[] initializers = aClass.getInitializers(); for (PsiClassInitializer initializer : initializers) { if (initializer.hasModifierProperty(PsiModifier.STATIC) == field.hasModifierProperty(PsiModifier.STATIC)) { final PsiCodeBlock body = initializer.getBody(); if (body == codeBlock) return null; try { final ControlFlow controlFlow = getControlFlow(body); if (!ControlFlowUtil.isVariableDefinitelyNotAssigned(field, controlFlow)) { alreadyAssigned = true; break; } } catch (AnalysisCanceledException e) { // incomplete code return null; } } } } if (!alreadyAssigned && !field.hasModifierProperty(PsiModifier.STATIC)) { // then check if instance field already assigned in other constructor final PsiMethod ctr = codeBlock.getParent() instanceof PsiMethod ? (PsiMethod) codeBlock.getParent() : null; // assignment to final field in several constructors threatens us only if these are linked // (there is this() call in the beginning) final List<PsiMethod> redirectedConstructors = ctr != null && ctr.isConstructor() ? JavaHighlightUtil.getChainedConstructors(ctr) : null; for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); PsiCodeBlock body = redirectedConstructor.getBody(); if (body != null && variableDefinitelyAssignedIn(variable, body)) { alreadyAssigned = true; break; } } } } if (alreadyAssigned) { String description = JavaErrorMessages.message("variable.already.assigned", variable.getName()); final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) .descriptionAndTooltip(description) .create(); QuickFixAction.registerQuickFixAction( highlightInfo, QUICK_FIX_FACTORY.createModifierListFix(variable, PsiModifier.FINAL, false, false)); QuickFixAction.registerQuickFixAction( highlightInfo, QUICK_FIX_FACTORY.createDeferFinalAssignmentFix(variable, expression)); return highlightInfo; } return null; }
private static boolean processCachedMembersByName( @NotNull PsiClass aClass, @NotNull PsiScopeProcessor processor, @NotNull ResolveState state, @Nullable Set<PsiClass> visited, PsiElement last, @NotNull PsiElement place, boolean isRaw, @NotNull PsiSubstitutor substitutor, @NotNull MembersMap value, String name, @NotNull LanguageLevel languageLevel) { final ElementClassHint classHint = processor.getHint(ElementClassHint.KEY); PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.FIELD)) { final PsiField fieldByName = aClass.findFieldByName(name, false); if (fieldByName != null) { processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); if (!processor.execute(fieldByName, state)) return false; } else { final Map<String, List<Pair<PsiMember, PsiSubstitutor>>> allFieldsMap = value.get(MemberType.FIELD); final List<Pair<PsiMember, PsiSubstitutor>> list = allFieldsMap.get(name); if (list != null) { for (final Pair<PsiMember, PsiSubstitutor> candidate : list) { PsiMember candidateField = candidate.getFirst(); PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor( candidateField.getContainingClass(), candidate.getSecond(), aClass, substitutor, factory, languageLevel); processor.handleEvent( PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, candidateField.getContainingClass()); if (!processor.execute(candidateField, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; } } } } if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) { if (last != null && last.getParent() == aClass) { if (last instanceof PsiClass) { if (!processor.execute(last, state)) return false; } // Parameters final PsiTypeParameterList list = aClass.getTypeParameterList(); if (list != null && !list.processDeclarations(processor, state, last, place)) return false; } if (!(last instanceof PsiReferenceList)) { final PsiClass classByName = aClass.findInnerClassByName(name, false); if (classByName != null) { processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); if (!processor.execute(classByName, state)) return false; } else { Map<String, List<Pair<PsiMember, PsiSubstitutor>>> allClassesMap = value.get(MemberType.CLASS); List<Pair<PsiMember, PsiSubstitutor>> list = allClassesMap.get(name); if (list != null) { for (final Pair<PsiMember, PsiSubstitutor> candidate : list) { PsiMember inner = candidate.getFirst(); PsiClass containingClass = inner.getContainingClass(); if (containingClass != null) { PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor( containingClass, candidate.getSecond(), aClass, substitutor, factory, languageLevel); processor.handleEvent( PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); if (!processor.execute(inner, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; } } } } } } if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD)) { if (processor instanceof MethodResolverProcessor) { final MethodResolverProcessor methodResolverProcessor = (MethodResolverProcessor) processor; if (methodResolverProcessor.isConstructor()) { final PsiMethod[] constructors = aClass.getConstructors(); methodResolverProcessor.handleEvent( PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); for (PsiMethod constructor : constructors) { if (!methodResolverProcessor.execute(constructor, state)) return false; } return true; } } Map<String, List<Pair<PsiMember, PsiSubstitutor>>> allMethodsMap = value.get(MemberType.METHOD); List<Pair<PsiMember, PsiSubstitutor>> list = allMethodsMap.get(name); if (list != null) { for (final Pair<PsiMember, PsiSubstitutor> candidate : list) { ProgressIndicatorProvider.checkCanceled(); PsiMethod candidateMethod = (PsiMethod) candidate.getFirst(); if (processor instanceof MethodResolverProcessor) { if (candidateMethod.isConstructor() != ((MethodResolverProcessor) processor).isConstructor()) continue; } final PsiClass containingClass = candidateMethod.getContainingClass(); if (visited != null && visited.contains(candidateMethod.getContainingClass())) { continue; } PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor( containingClass, candidate.getSecond(), aClass, substitutor, factory, languageLevel); finalSubstitutor = checkRaw(isRaw, factory, candidateMethod, finalSubstitutor); processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); if (!processor.execute(candidateMethod, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; } if (visited != null) { for (Pair<PsiMember, PsiSubstitutor> aList : list) { visited.add(aList.getFirst().getContainingClass()); } } } } return true; }
private void checkMember(@NotNull final PsiMember member) { if (member.hasModifierProperty(PsiModifier.PRIVATE) || member.hasModifierProperty(PsiModifier.NATIVE)) return; if (member instanceof PsiMethod && member instanceof SyntheticElement || !member.isPhysical()) return; if (member instanceof PsiMethod) { PsiMethod method = (PsiMethod) member; if (!method.getHierarchicalMethodSignature().getSuperSignatures().isEmpty()) { log(member.getName() + " overrides"); return; // overrides } if (MethodUtils.isOverridden(method)) { log(member.getName() + " overridden"); return; } } if (member instanceof PsiEnumConstant) return; if (member instanceof PsiClass && (member instanceof PsiAnonymousClass || member instanceof PsiTypeParameter || member instanceof PsiSyntheticClass || PsiUtil.isLocalClass((PsiClass) member))) { return; } final PsiClass memberClass = member.getContainingClass(); if (memberClass != null && (memberClass.isInterface() || memberClass.isEnum() || memberClass.isAnnotationType() || PsiUtil.isLocalClass(memberClass) && member instanceof PsiClass)) { return; } final PsiFile memberFile = member.getContainingFile(); Project project = memberFile.getProject(); if (myDeadCodeInspection.isEntryPoint(member)) { log(member.getName() + " is entry point"); return; } PsiModifierList memberModifierList = member.getModifierList(); if (memberModifierList == null) return; final int currentLevel = PsiUtil.getAccessLevel(memberModifierList); final AtomicInteger maxLevel = new AtomicInteger(PsiUtil.ACCESS_LEVEL_PRIVATE); final AtomicBoolean foundUsage = new AtomicBoolean(); PsiDirectory memberDirectory = memberFile.getContainingDirectory(); final PsiPackage memberPackage = memberDirectory == null ? null : JavaDirectoryService.getInstance().getPackage(memberDirectory); log(member.getName() + ": checking effective level for " + member); boolean result = UnusedSymbolUtil.processUsages( project, memberFile, member, new EmptyProgressIndicator(), null, new Processor<UsageInfo>() { @Override public boolean process(UsageInfo info) { foundUsage.set(true); PsiFile psiFile = info.getFile(); if (psiFile == null) return true; if (!(psiFile instanceof PsiJavaFile)) { log(" refd from " + psiFile.getName() + "; set to public"); maxLevel.set(PsiUtil.ACCESS_LEVEL_PUBLIC); if (memberClass != null) { childMembersAreUsedOutsideMyPackage.add(memberClass); } return false; // referenced from XML, has to be public } // int offset = info.getNavigationOffset(); // if (offset == -1) return true; PsiElement element = info.getElement(); if (element == null) return true; @PsiUtil.AccessLevel int level = getEffectiveLevel(element, psiFile, memberFile, memberClass, memberPackage); log( " ref in file " + psiFile.getName() + "; level = " + PsiUtil.getAccessModifier(level) + "; (" + element + ")"); while (true) { int oldLevel = maxLevel.get(); if (level <= oldLevel || maxLevel.compareAndSet(oldLevel, level)) break; } if (level == PsiUtil.ACCESS_LEVEL_PUBLIC && memberClass != null) { childMembersAreUsedOutsideMyPackage.add(memberClass); } return level != PsiUtil.ACCESS_LEVEL_PUBLIC; } }); if (!foundUsage.get()) { log(member.getName() + " unused; ignore"); return; // do not propose private for unused method } int max = maxLevel.get(); if (max == PsiUtil.ACCESS_LEVEL_PRIVATE && memberClass == null) { max = PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL; } log(member.getName() + ": effective level is '" + PsiUtil.getAccessModifier(max) + "'"); if (max < currentLevel) { if (max == PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL && member instanceof PsiClass && childMembersAreUsedOutsideMyPackage.contains(member)) { log(member.getName() + " children used outside my package; ignore"); return; // e.g. some public method is used outside my package (without importing class) } PsiElement toHighlight = currentLevel == PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL ? ((PsiNameIdentifierOwner) member).getNameIdentifier() : ContainerUtil.find( memberModifierList.getChildren(), new Condition<PsiElement>() { @Override public boolean value(PsiElement element) { return element instanceof PsiKeyword && element.getText().equals(PsiUtil.getAccessModifier(currentLevel)); } }); assert toHighlight != null : member + " ; " + ((PsiNameIdentifierOwner) member).getNameIdentifier() + "; " + memberModifierList.getText(); myHolder.registerProblem( toHighlight, "Access can be " + PsiUtil.getAccessModifier(max), new ChangeModifierFix(PsiUtil.getAccessModifier(max))); } }