public static void registerQuickFix(
     PsiMember refElement,
     PsiJavaCodeReferenceElement place,
     PsiClass accessObjectClass,
     HighlightInfo error) {
   if (refElement instanceof PsiField && place instanceof PsiReferenceExpression) {
     final PsiField psiField = (PsiField) refElement;
     final PsiClass containingClass = psiField.getContainingClass();
     if (containingClass != null) {
       if (PsiUtil.isOnAssignmentLeftHand((PsiExpression) place)) {
         final PsiMethod setterPrototype = PropertyUtil.generateSetterPrototype(psiField);
         final PsiMethod setter = containingClass.findMethodBySignature(setterPrototype, true);
         if (setter != null && PsiUtil.isAccessible(setter, place, accessObjectClass)) {
           QuickFixAction.registerQuickFixAction(
               error, new ReplaceInaccessibleFieldWithGetterSetterFix(place, setter, true));
         }
       } else if (PsiUtil.isAccessedForReading((PsiExpression) place)) {
         final PsiMethod getterPrototype = PropertyUtil.generateGetterPrototype(psiField);
         final PsiMethod getter = containingClass.findMethodBySignature(getterPrototype, true);
         if (getter != null && PsiUtil.isAccessible(getter, place, accessObjectClass)) {
           QuickFixAction.registerQuickFixAction(
               error, new ReplaceInaccessibleFieldWithGetterSetterFix(place, getter, false));
         }
       }
     }
   }
 }
  @Nullable
  public EncapsulateFieldUsageInfo createUsage(
      @NotNull EncapsulateFieldsDescriptor descriptor,
      @NotNull FieldDescriptor fieldDescriptor,
      @NotNull PsiReference reference) {
    if (!(reference instanceof PsiReferenceExpression)) return null;

    boolean findSet = descriptor.isToEncapsulateSet();
    boolean findGet = descriptor.isToEncapsulateGet();
    PsiReferenceExpression ref = (PsiReferenceExpression) reference;
    // [Jeka] to avoid recursion in the field's accessors
    if (findGet
        && isUsedInExistingAccessor(
            descriptor.getTargetClass(), fieldDescriptor.getGetterPrototype(), ref)) return null;
    if (findSet
        && isUsedInExistingAccessor(
            descriptor.getTargetClass(), fieldDescriptor.getSetterPrototype(), ref)) return null;
    if (!findGet) {
      if (!PsiUtil.isAccessedForWriting(ref)) return null;
    }
    if (!findSet || fieldDescriptor.getField().hasModifierProperty(PsiModifier.FINAL)) {
      if (!PsiUtil.isAccessedForReading(ref)) return null;
    }
    if (!descriptor.isToUseAccessorsWhenAccessible()) {
      PsiModifierList newModifierList = createNewModifierList(descriptor);

      PsiClass accessObjectClass = null;
      PsiExpression qualifier = ref.getQualifierExpression();
      if (qualifier != null) {
        accessObjectClass = (PsiClass) PsiUtil.getAccessObjectClass(qualifier).getElement();
      }
      final PsiResolveHelper helper =
          JavaPsiFacade.getInstance(((PsiReferenceExpression) reference).getProject())
              .getResolveHelper();
      if (helper.isAccessible(
          fieldDescriptor.getField(), newModifierList, ref, accessObjectClass, null)) {
        return null;
      }
    }
    return new EncapsulateFieldUsageInfo(ref, fieldDescriptor);
  }
Ejemplo n.º 3
0
 public boolean isReferencedForRead(@NotNull PsiVariable variable) {
   List<PsiReference> array;
   synchronized (myLocalRefsMap) {
     array = myLocalRefsMap.getKeysByValue(variable);
   }
   if (array == null) return false;
   for (PsiReference ref : array) {
     PsiElement refElement = ref.getElement();
     if (!(refElement instanceof PsiExpression)) { // possible with incomplete code
       return true;
     }
     if (PsiUtil.isAccessedForReading((PsiExpression) refElement)) {
       if (refElement.getParent() instanceof PsiExpression
           && refElement.getParent().getParent() instanceof PsiExpressionStatement
           && PsiUtil.isAccessedForWriting((PsiExpression) refElement)) {
         continue; // "var++;"
       }
       return true;
     }
   }
   return false;
 }
  public static boolean isEffectivelyFinal(
      @NotNull PsiVariable variable,
      @NotNull PsiElement scope,
      @Nullable PsiJavaCodeReferenceElement context) {
    boolean effectivelyFinal;
    if (variable instanceof PsiParameter) {
      effectivelyFinal =
          notAccessedForWriting(
              variable, new LocalSearchScope(((PsiParameter) variable).getDeclarationScope()));
    } else {
      final ControlFlow controlFlow;
      try {
        PsiElement codeBlock = PsiUtil.getVariableCodeBlock(variable, context);
        if (codeBlock == null) return true;
        controlFlow = getControlFlow(codeBlock);
      } catch (AnalysisCanceledException e) {
        return true;
      }

      final List<PsiReferenceExpression> readBeforeWriteLocals =
          ControlFlowUtil.getReadBeforeWriteLocals(controlFlow);
      for (PsiReferenceExpression expression : readBeforeWriteLocals) {
        if (expression.resolve() == variable) {
          return PsiUtil.isAccessedForReading(expression);
        }
      }

      final Collection<ControlFlowUtil.VariableInfo> initializedTwice =
          ControlFlowUtil.getInitializedTwice(controlFlow);
      effectivelyFinal =
          !initializedTwice.contains(new ControlFlowUtil.VariableInfo(variable, null));
      if (effectivelyFinal) {
        effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(scope));
      }
    }
    return effectivelyFinal;
  }
  @Nullable
  public static HighlightInfo checkVariableInitializedBeforeUsage(
      @NotNull PsiReferenceExpression expression,
      @NotNull PsiVariable variable,
      @NotNull Map<PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems,
      @NotNull PsiFile containingFile) {
    if (variable instanceof ImplicitVariable) return null;
    if (!PsiUtil.isAccessedForReading(expression)) return null;
    int startOffset = expression.getTextRange().getStartOffset();
    final PsiElement topBlock;
    if (variable.hasInitializer()) {
      topBlock = PsiUtil.getVariableCodeBlock(variable, variable);
      if (topBlock == null) return null;
    } else {
      PsiElement scope =
          variable instanceof PsiField
              ? ((PsiField) variable).getContainingClass()
              : variable.getParent() != null ? variable.getParent().getParent() : null;
      if (scope instanceof PsiCodeBlock && scope.getParent() instanceof PsiSwitchStatement) {
        scope = PsiTreeUtil.getParentOfType(scope, PsiCodeBlock.class);
      }

      topBlock =
          FileTypeUtils.isInServerPageFile(scope) && scope instanceof PsiFile
              ? scope
              : PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope);
      if (variable instanceof PsiField) {
        // non final field already initialized with default value
        if (!variable.hasModifierProperty(PsiModifier.FINAL)) return null;
        // final field may be initialized in ctor or class initializer only
        // if we're inside non-ctr method, skip it
        if (PsiUtil.findEnclosingConstructorOrInitializer(expression) == null
            && HighlightUtil.findEnclosingFieldInitializer(expression) == null) {
          return null;
        }
        if (topBlock == null) return null;
        final PsiElement parent = topBlock.getParent();
        // access to final fields from inner classes always allowed
        if (inInnerClass(expression, ((PsiField) variable).getContainingClass(), containingFile))
          return null;
        final PsiCodeBlock block;
        final PsiClass aClass;
        if (parent instanceof PsiMethod) {
          PsiMethod constructor = (PsiMethod) parent;
          if (!containingFile
              .getManager()
              .areElementsEquivalent(
                  constructor.getContainingClass(), ((PsiField) variable).getContainingClass()))
            return null;
          // static variables already initialized in class initializers
          if (variable.hasModifierProperty(PsiModifier.STATIC)) return null;
          // as a last chance, field may be initialized in this() call
          final List<PsiMethod> redirectedConstructors =
              JavaHighlightUtil.getChainedConstructors(constructor);
          for (int j = 0;
              redirectedConstructors != null && j < redirectedConstructors.size();
              j++) {
            PsiMethod redirectedConstructor = redirectedConstructors.get(j);
            // variable must be initialized before its usage
            // ???
            // if (startOffset < redirectedConstructor.getTextRange().getStartOffset()) continue;
            PsiCodeBlock body = redirectedConstructor.getBody();
            if (body != null && variableDefinitelyAssignedIn(variable, body)) {
              return null;
            }
          }
          block = constructor.getBody();
          aClass = constructor.getContainingClass();
        } else if (parent instanceof PsiClassInitializer) {
          final PsiClassInitializer classInitializer = (PsiClassInitializer) parent;
          if (!containingFile
              .getManager()
              .areElementsEquivalent(
                  classInitializer.getContainingClass(),
                  ((PsiField) variable).getContainingClass())) return null;
          block = classInitializer.getBody();
          aClass = classInitializer.getContainingClass();
        } else {
          // field reference outside code block
          // check variable initialized before its usage
          final PsiField field = (PsiField) variable;

          aClass = field.getContainingClass();
          if (aClass == null
              || isFieldInitializedInOtherFieldInitializer(
                  aClass, field, field.hasModifierProperty(PsiModifier.STATIC))) {
            return null;
          }
          final PsiField anotherField =
              PsiTreeUtil.getTopmostParentOfType(expression, PsiField.class);
          int offset = startOffset;
          if (anotherField != null
              && anotherField.getContainingClass() == aClass
              && !field.hasModifierProperty(PsiModifier.STATIC)) {
            offset = 0;
          }
          block = null;
          // initializers will be checked later
          final PsiMethod[] constructors = aClass.getConstructors();
          for (PsiMethod constructor : constructors) {
            // variable must be initialized before its usage
            if (offset < constructor.getTextRange().getStartOffset()) continue;
            PsiCodeBlock body = constructor.getBody();
            if (body != null && variableDefinitelyAssignedIn(variable, body)) {
              return null;
            }
            // as a last chance, field may be initialized in this() call
            final List<PsiMethod> redirectedConstructors =
                JavaHighlightUtil.getChainedConstructors(constructor);
            for (int j = 0;
                redirectedConstructors != null && j < redirectedConstructors.size();
                j++) {
              PsiMethod redirectedConstructor = redirectedConstructors.get(j);
              // variable must be initialized before its usage
              if (offset < redirectedConstructor.getTextRange().getStartOffset()) continue;
              PsiCodeBlock redirectedBody = redirectedConstructor.getBody();
              if (redirectedBody != null
                  && variableDefinitelyAssignedIn(variable, redirectedBody)) {
                return null;
              }
            }
          }
        }

        if (aClass != null) {
          // field may be initialized in class initializer
          final PsiClassInitializer[] initializers = aClass.getInitializers();
          for (PsiClassInitializer initializer : initializers) {
            PsiCodeBlock body = initializer.getBody();
            if (body == block) break;
            // variable referenced in initializer must be initialized in initializer preceding
            // assignment
            // variable referenced in field initializer or in class initializer
            boolean shouldCheckInitializerOrder =
                block == null || block.getParent() instanceof PsiClassInitializer;
            if (shouldCheckInitializerOrder
                && startOffset < initializer.getTextRange().getStartOffset()) continue;
            if (initializer.hasModifierProperty(PsiModifier.STATIC)
                == variable.hasModifierProperty(PsiModifier.STATIC)) {
              if (variableDefinitelyAssignedIn(variable, body)) return null;
            }
          }
        }
      }
    }
    if (topBlock == null) return null;
    Collection<PsiReferenceExpression> codeBlockProblems = uninitializedVarProblems.get(topBlock);
    if (codeBlockProblems == null) {
      try {
        final ControlFlow controlFlow = getControlFlow(topBlock);
        codeBlockProblems = ControlFlowUtil.getReadBeforeWriteLocals(controlFlow);
      } catch (AnalysisCanceledException | IndexNotReadyException e) {
        codeBlockProblems = Collections.emptyList();
      }
      uninitializedVarProblems.put(topBlock, codeBlockProblems);
    }
    if (codeBlockProblems.contains(expression)) {
      final String name = expression.getElement().getText();
      String description = JavaErrorMessages.message("variable.not.initialized", name);
      HighlightInfo highlightInfo =
          HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
              .range(expression)
              .descriptionAndTooltip(description)
              .create();
      QuickFixAction.registerQuickFixAction(
          highlightInfo, QUICK_FIX_FACTORY.createAddVariableInitializerFix(variable));
      if (variable instanceof PsiField) {
        QuickFixAction.registerQuickFixAction(
            highlightInfo,
            QUICK_FIX_FACTORY.createModifierListFix(variable, PsiModifier.FINAL, false, false));
      }
      return highlightInfo;
    }

    return null;
  }
 @Override
 public void visitReferenceExpression(PsiReferenceExpression expression) {
   if (myWritten && myRead) {
     return;
   }
   super.visitReferenceExpression(expression);
   final PsiElement target = expression.resolve();
   if (target != myVariable) {
     return;
   }
   if (PsiUtil.isAccessedForWriting(expression)) {
     final PsiElement parent =
         PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class);
     if (parent instanceof PsiAssignmentExpression) {
       final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression) parent;
       final PsiExpression rhs = assignmentExpression.getRExpression();
       if (isComplexArrayExpression(rhs)) {
         myWritten = true;
         myRead = true;
       } else if (!isSimpleArrayExpression(rhs)) {
         myWritten = true;
       }
     }
     return;
   }
   myIsReferenced = true;
   PsiElement parent = getParent(expression);
   if (parent instanceof PsiArrayAccessExpression) {
     PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression) parent;
     parent = getParent(parent);
     while (parent instanceof PsiArrayAccessExpression) {
       arrayAccessExpression = (PsiArrayAccessExpression) parent;
       parent = getParent(parent);
     }
     final PsiType type = arrayAccessExpression.getType();
     if (type != null) {
       final int dimensions = type.getArrayDimensions();
       if (dimensions > 0 && dimensions != myVariable.getType().getArrayDimensions()) {
         myWritten = true;
       }
     }
     if (PsiUtil.isAccessedForWriting(arrayAccessExpression)) {
       myWritten = true;
     }
     if (PsiUtil.isAccessedForReading(arrayAccessExpression)) {
       myRead = true;
     }
   } else if (parent instanceof PsiReferenceExpression) {
     final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) parent;
     final String name = referenceExpression.getReferenceName();
     if ("length".equals(name)
         || ("clone".equals(name)
             && referenceExpression.getParent() instanceof PsiMethodCallExpression)) {
       myRead = true;
     }
   } else if (parent instanceof PsiForeachStatement) {
     final PsiForeachStatement foreachStatement = (PsiForeachStatement) parent;
     final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
     if (PsiTreeUtil.isAncestor(iteratedValue, expression, false)) {
       myRead = true;
     }
   } else if (parent instanceof PsiExpressionList) {
     final PsiExpressionList expressionList = (PsiExpressionList) parent;
     parent = parent.getParent();
     if (parent instanceof PsiMethodCallExpression) {
       final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) parent;
       final PsiMethod method = methodCallExpression.resolveMethod();
       if (method != null) {
         final PsiClass aClass = method.getContainingClass();
         if (aClass != null) {
           final String methodName = method.getName();
           final String qualifiedName = aClass.getQualifiedName();
           if ("java.lang.System".equals(qualifiedName)) {
             if ("arraycopy".equals(methodName)) {
               final PsiExpression[] expressions = expressionList.getExpressions();
               if (expressions.length == 5) {
                 if (PsiTreeUtil.isAncestor(expressions[0], expression, false)) {
                   myRead = true;
                   return;
                 } else if (PsiTreeUtil.isAncestor(expressions[2], expression, false)) {
                   myWritten = true;
                   return;
                 }
               }
             }
           } else if (CommonClassNames.JAVA_UTIL_ARRAYS.equals(qualifiedName)) {
             if ("fill".equals(methodName)
                 || "parallelPrefix".equals(methodName)
                 || "parallelSetAll".equals(methodName)
                 || "parallelSort".equals(methodName)
                 || "setAll".equals(methodName)
                 || "sort".equals(methodName)) {
               myWritten = true;
             } else {
               myRead = true;
             }
             return;
           }
         }
       }
     }
     myRead = true;
     myWritten = true;
   } else {
     myWritten = true;
     myRead = true;
   }
 }