@NotNull
  public TypeInfoForCall getQualifiedExpressionExtendedTypeInfo(
      @NotNull JetQualifiedExpression expression,
      @NotNull ResolutionContext context,
      @NotNull ResolveMode resolveMode) {
    // TODO : functions as values
    JetExpression selectorExpression = expression.getSelectorExpression();
    JetExpression receiverExpression = expression.getReceiverExpression();
    JetTypeInfo receiverTypeInfo =
        expressionTypingServices.getTypeInfoWithNamespaces(
            receiverExpression,
            context.scope,
            NO_EXPECTED_TYPE,
            context.dataFlowInfo,
            context.trace);
    JetType receiverType = receiverTypeInfo.getType();
    if (selectorExpression == null) return TypeInfoForCall.create(null, context.dataFlowInfo);
    if (receiverType == null)
      receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());

    context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());

    if (selectorExpression instanceof JetSimpleNameExpression) {
      ConstantUtils.propagateConstantValues(
          expression, context.trace, (JetSimpleNameExpression) selectorExpression);
    }

    TypeInfoForCall selectorReturnTypeInfo =
        getSelectorReturnTypeInfo(
            new ExpressionReceiver(receiverExpression, receiverType),
            expression.getOperationTokenNode(),
            selectorExpression,
            context,
            resolveMode);
    JetType selectorReturnType = selectorReturnTypeInfo.getType();

    // TODO move further
    if (!(receiverType instanceof NamespaceType)
        && expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
      if (selectorReturnType != null
          && !selectorReturnType.isNullable()
          && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) {
        if (receiverType.isNullable()) {
          selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
        }
      }
    }

    // TODO : this is suspicious: remove this code?
    if (selectorReturnType != null) {
      context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
    }
    JetTypeInfo typeInfo =
        JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
    if (resolveMode == ResolveMode.TOP_LEVEL_CALL) {
      DataFlowUtils.checkType(typeInfo.getType(), expression, context, typeInfo.getDataFlowInfo());
    }
    return TypeInfoForCall.create(typeInfo, selectorReturnTypeInfo);
  }
 @Nullable
 private JetType lookupNamespaceOrClassObject(
     @NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) {
   Name referencedName = expression.getReferencedNameAsName();
   ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
   if (classifier != null) {
     JetType classObjectType = classifier.getClassObjectType();
     if (classObjectType != null) {
       context.trace.record(REFERENCE_TARGET, expression, classifier);
       JetType result;
       if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT
           && classifier instanceof ClassDescriptor) {
         JetScope scope =
             new ChainedScope(
                 classifier,
                 classObjectType.getMemberScope(),
                 getStaticNestedClassesScope((ClassDescriptor) classifier));
         result = new NamespaceType(referencedName, scope);
       } else if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT
           || classifier.isClassObjectAValue()) {
         result = classObjectType;
       } else {
         context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
         result = null;
       }
       return DataFlowUtils.checkType(result, expression, context);
     }
   }
   JetType[] result = new JetType[1];
   TemporaryBindingTrace temporaryTrace =
       TemporaryBindingTrace.create(
           context.trace, "trace for namespace/class object lookup of name", referencedName);
   if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) {
     temporaryTrace.commit();
     return DataFlowUtils.checkType(result[0], expression, context);
   }
   // To report NO_CLASS_OBJECT when no namespace found
   if (classifier != null) {
     if (context.expressionPosition == ExpressionPosition.FREE) {
       context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
     }
     context.trace.record(REFERENCE_TARGET, expression, classifier);
     JetScope scopeForStaticMembersResolution =
         classifier instanceof ClassDescriptor
             ? getStaticNestedClassesScope((ClassDescriptor) classifier)
             : JetScope.EMPTY;
     return new NamespaceType(referencedName, scopeForStaticMembersResolution);
   }
   temporaryTrace.commit();
   return result[0];
 }
  @Nullable
  private JetType getExtendedClassObjectType(
      @NotNull JetType classObjectType,
      @NotNull Name referencedName,
      @NotNull ClassifierDescriptor classifier,
      @NotNull ResolutionContext context) {
    if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT
        && classifier instanceof ClassDescriptor) {
      List<JetScope> scopes = new ArrayList<JetScope>(3);

      scopes.add(classObjectType.getMemberScope());
      scopes.add(getStaticNestedClassesScope((ClassDescriptor) classifier));

      NamespaceDescriptor namespace = context.scope.getNamespace(referencedName);
      if (namespace != null) {
        scopes.add(namespace.getMemberScope());
      }

      JetScope scope = new ChainedScope(classifier, scopes.toArray(new JetScope[scopes.size()]));
      return new NamespaceType(referencedName, scope);
    } else if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT
        || classifier.isClassObjectAValue()) {
      return classObjectType;
    } else {
      return null;
    }
  }