@Override
  public void visitReferenceExpression(@NotNull GrReferenceExpression referenceExpression) {
    final GrExpression qualifier = referenceExpression.getQualifier();
    final GroovyResolveResult resolveResult = referenceExpression.advancedResolve();
    final PsiElement resolved = resolveResult.getElement();
    final String referenceName = referenceExpression.getReferenceName();

    if (PsiUtil.isThisOrSuperRef(referenceExpression)) {
      writeThisOrSuperRef(referenceExpression, qualifier, referenceName);
      return;
    }

    if (ResolveUtil.isClassReference(referenceExpression)) {
      // just delegate to qualifier
      LOG.assertTrue(qualifier != null);
      qualifier.accept(this);
      return;
    }

    if (resolved instanceof PsiClass) {
      builder.append(((PsiClass)resolved).getQualifiedName());
      if (PsiUtil.isExpressionUsed(referenceExpression)) {
        builder.append(".class");
      }
      return;
    }

    //don't try to resolve local vars that are provided my this generator (they are listed in myUsedVarNames)
    if (resolved == null && qualifier == null && context.myUsedVarNames.contains(referenceName)) {
      builder.append(referenceName);
      return;
    }

    //all refs in script that are not resolved are saved in 'binding' of the script
    if (qualifier == null &&
        (resolved == null ||
         resolved instanceof LightElement && !(resolved instanceof ClosureSyntheticParameter)) &&
        (referenceExpression.getParent() instanceof GrIndexProperty || !(referenceExpression.getParent() instanceof GrCall)) &&
        PsiUtil.getContextClass(referenceExpression) instanceof GroovyScriptClass) {
      final GrExpression thisExpr = factory.createExpressionFromText("this", referenceExpression);
      thisExpr.accept(this);
      builder.append(".getBinding().getProperty(\"").append(referenceExpression.getReferenceName()).append("\")");
      return;
    }

    final IElementType type = referenceExpression.getDotTokenType();

    GrExpression qualifierToUse = qualifier;

    if (type == GroovyTokenTypes.mMEMBER_POINTER) {
      LOG.assertTrue(qualifier != null);
      builder.append("new ").append(GroovyCommonClassNames.ORG_CODEHAUS_GROOVY_RUNTIME_METHOD_CLOSURE).append('(');
      qualifier.accept(this);
      builder.append(", \"").append(referenceName).append("\")");
      return;
    }

    if (type == GroovyTokenTypes.mOPTIONAL_DOT || qualifierHasSafeChain(referenceExpression)) {
      LOG.assertTrue(qualifier != null);

      String qualifierName = createVarByInitializer(qualifier);
      builder.append('(').append(qualifierName).append(" == null ? null : ");

      qualifierToUse = factory.createReferenceExpressionFromText(qualifierName, referenceExpression);
    }


    if (resolveResult.isInvokedOnProperty() && resolved instanceof PsiMethod) {
      //property-style access to accessor (e.g. qual.prop should be translated to qual.getProp())
      LOG.assertTrue(GroovyPropertyUtils.isSimplePropertyGetter((PsiMethod)resolved));
      invokeMethodOn(
        ((PsiMethod)resolved),
        qualifierToUse,
        GrExpression.EMPTY_ARRAY,
        GrNamedArgument.EMPTY_ARRAY,
        GrClosableBlock.EMPTY_ARRAY,
        resolveResult.getSubstitutor(),
        referenceExpression
      );
    }
    else {
      if (qualifierToUse != null) {
        qualifierToUse.accept(this);
        builder.append('.');
      }

      if (resolved instanceof PsiNamedElement && !(resolved instanceof GrBindingVariable)) {
        final String refName = ((PsiNamedElement)resolved).getName();

        if (resolved instanceof GrVariable && context.analyzedVars.toWrap((GrVariable)resolved)) {
          //this var should be wrapped by groovy.lang.Reference. so we add .get() tail.
          builder.append(context.analyzedVars.toVarName((GrVariable)resolved));
          if (!PsiUtil.isAccessedForWriting(referenceExpression)) {
            builder.append(".get()");
          }
        }
        else {
          builder.append(refName);
        }
      }
      else {
        //unresolved reference
        if (referenceName != null) {
          if (PsiUtil.isAccessedForWriting(referenceExpression)) {
            builder.append(referenceName);
          }
          else {
            PsiType stringType = PsiType.getJavaLangString(referenceExpression.getManager(), referenceExpression.getResolveScope());
            PsiType qualifierType = PsiImplUtil.getQualifierType(referenceExpression);
            GroovyResolveResult[] candidates = qualifierType != null
                                               ? ResolveUtil.getMethodCandidates(qualifierType, "getProperty", referenceExpression,
                                                                                 stringType)
                                               : GroovyResolveResult.EMPTY_ARRAY;
            final PsiElement method = PsiImplUtil.extractUniqueElement(candidates);
            if (method != null) {
              builder.append("getProperty(\"").append(referenceName).append("\")");
            }
            else {
              builder.append(referenceName);
            }
          }
        }
        else {
          final PsiElement nameElement = referenceExpression.getReferenceNameElement();
          if (nameElement instanceof GrExpression) {
            ((GrExpression)nameElement).accept(this);
          }
          else if (nameElement != null) {
            builder.append(nameElement.toString());
          }
        }
      }
    }

    if (type == GroovyTokenTypes.mOPTIONAL_DOT || qualifierHasSafeChain(referenceExpression)) {
      builder.append(')');
    }

  }
@Override
  public void visitReferenceExpression(@NotNull GrReferenceExpression referenceExpression)