private static void encodeContextInfo(PsiElement scope,
                                        PsiElement topLevelScope,
                                        boolean includeRefClasses,
                                        boolean canChangeQualifier) {
    if (scope instanceof StubBasedPsiElement) {
      // as long as "scope" is reachable, don't let GC collect AST together with all the copyable user data
      scope.putUserData(HARD_REF_TO_AST, scope.getNode());
    }

    if (scope instanceof PsiThisExpression){
      scope.putCopyableUserData(ENCODED_KEY, "");

      PsiThisExpression thisExpr = (PsiThisExpression)scope;
      final PsiJavaCodeReferenceElement qualifier = thisExpr.getQualifier();
      if (qualifier == null){
        PsiClass thisClass = RefactoringChangeUtil.getThisClass(thisExpr);
        if (thisClass != null && !(thisClass instanceof PsiAnonymousClass)){
          thisExpr.putCopyableUserData(THIS_QUALIFIER_CLASS_KEY, thisClass);
        }
      }
      else {
        final PsiElement resolved = qualifier.resolve();
        if (resolved instanceof PsiClass && resolved == topLevelScope) {
          thisExpr.putCopyableUserData(THIS_QUALIFIER_CLASS_KEY, (PsiClass)topLevelScope);
        }
      }
    }
    else if (scope instanceof PsiReferenceExpression){
      scope.putCopyableUserData(ENCODED_KEY, "");

      PsiReferenceExpression refExpr = (PsiReferenceExpression)scope;
      PsiExpression qualifier = refExpr.getQualifierExpression();
      if (qualifier == null){
        final JavaResolveResult resolveResult = refExpr.advancedResolve(false);
        final PsiElement refElement = resolveResult.getElement();
        if (refElement != null && !PsiTreeUtil.isAncestor(topLevelScope, refElement, false)){
          if (refElement instanceof PsiClass){
            if (includeRefClasses){
              refExpr.putCopyableUserData(REF_CLASS_KEY, (PsiClass)refElement);
            }
          }
          else if (refElement instanceof PsiMember && 
                   !Objects.equals(((PsiMember)refElement).getContainingClass(), topLevelScope)) {
            refExpr.putCopyableUserData(REF_MEMBER_KEY, ( (PsiMember)refElement));
            final PsiElement resolveScope = resolveResult.getCurrentFileResolveScope();
            if (resolveScope instanceof PsiClass && !PsiTreeUtil.isAncestor(topLevelScope, resolveScope, false)) {
              refExpr.putCopyableUserData(REF_MEMBER_THIS_CLASS_KEY, (PsiClass)resolveScope);
            }
          }
        }
      }
      else if (canChangeQualifier) {
        refExpr.putCopyableUserData(CAN_REMOVE_QUALIFIER_KEY, canRemoveQualifier(refExpr));
      }
    }
    else if (includeRefClasses) {
      PsiReference ref = scope.getReference();
      if (ref != null){
        scope.putCopyableUserData(ENCODED_KEY, "");

        PsiElement refElement = ref.resolve();
        if (refElement instanceof PsiClass && !PsiTreeUtil.isAncestor(topLevelScope, refElement, false)){
          scope.putCopyableUserData(REF_CLASS_KEY, (PsiClass)refElement);
        }
      }
    }

    for(PsiElement child = scope.getFirstChild(); child != null; child = child.getNextSibling()){
      encodeContextInfo(child, topLevelScope, includeRefClasses, canChangeQualifier);
    }
  }
private static void encodeContextInfo(PsiElement scope,
                                        PsiElement topLevelScope,
                                        boolean includeRefClasses,
                                        boolean canChangeQualifier)