public static void reportCyclicInheritanceHierarchyError(
      @NotNull BindingTrace trace,
      @NotNull ClassDescriptor classDescriptor,
      @NotNull ClassDescriptor superclass) {
    PsiElement psiElement =
        BindingContextUtils.classDescriptorToDeclaration(
            trace.getBindingContext(), classDescriptor);

    PsiElement elementToMark = null;
    if (psiElement instanceof JetClassOrObject) {
      JetClassOrObject classOrObject = (JetClassOrObject) psiElement;
      for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
        JetTypeReference typeReference = delegationSpecifier.getTypeReference();
        if (typeReference == null) continue;
        JetType supertype = trace.get(TYPE, typeReference);
        if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
          elementToMark = typeReference;
        }
      }
    }
    if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
      PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
      PsiElement nameIdentifier = namedElement.getNameIdentifier();
      if (nameIdentifier != null) {
        elementToMark = nameIdentifier;
      }
    }
    if (elementToMark != null) {
      trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
    }
  }
Esempio n. 2
0
  private void resolveDelegationSpecifierList(
      final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) {
    if (!context.completeAnalysisNeeded(jetClass)) return;
    final ConstructorDescriptor primaryConstructor =
        descriptor.getUnsubstitutedPrimaryConstructor();
    final JetScope scopeForConstructor =
        primaryConstructor == null
            ? null
            : FunctionDescriptorUtil.getFunctionInnerScope(
                descriptor.getScopeForSupertypeResolution(), primaryConstructor, trace);
    final ExpressionTypingServices typeInferrer = expressionTypingServices; // TODO : flow

    final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
    JetVisitorVoid visitor =
        new JetVisitorVoid() {
          private void recordSupertype(JetTypeReference typeReference, JetType supertype) {
            if (supertype == null) return;
            supertypes.put(typeReference, supertype);
          }

          @Override
          public void visitDelegationByExpressionSpecifier(
              JetDelegatorByExpressionSpecifier specifier) {
            if (descriptor.getKind() == ClassKind.TRAIT) {
              trace.report(DELEGATION_IN_TRAIT.on(specifier));
            }
            JetType supertype =
                trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
            recordSupertype(specifier.getTypeReference(), supertype);
            if (supertype != null) {
              DeclarationDescriptor declarationDescriptor =
                  supertype.getConstructor().getDeclarationDescriptor();
              if (declarationDescriptor instanceof ClassDescriptor) {
                ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
                if (classDescriptor.getKind() != ClassKind.TRAIT) {
                  trace.report(DELEGATION_NOT_TO_TRAIT.on(specifier.getTypeReference()));
                }
              }
            }
            JetExpression delegateExpression = specifier.getDelegateExpression();
            if (delegateExpression != null) {
              JetScope scope =
                  scopeForConstructor == null
                      ? descriptor.getScopeForMemberResolution()
                      : scopeForConstructor;
              JetType type =
                  typeInferrer.getType(scope, delegateExpression, NO_EXPECTED_TYPE, trace);
              if (type != null
                  && supertype != null
                  && !JetTypeChecker.INSTANCE.isSubtypeOf(type, supertype)) {
                trace.report(TYPE_MISMATCH.on(delegateExpression, supertype, type));
              }
            }
          }

          @Override
          public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
            JetValueArgumentList valueArgumentList = call.getValueArgumentList();
            PsiElement elementToMark = valueArgumentList == null ? call : valueArgumentList;
            if (descriptor.getKind() == ClassKind.TRAIT) {
              trace.report(SUPERTYPE_INITIALIZED_IN_TRAIT.on(elementToMark));
            }
            JetTypeReference typeReference = call.getTypeReference();
            if (typeReference == null) return;
            if (descriptor.getUnsubstitutedPrimaryConstructor() == null) {
              assert descriptor.getKind() == ClassKind.TRAIT;
              return;
            }
            OverloadResolutionResults<FunctionDescriptor> results =
                callResolver.resolveFunctionCall(
                    trace,
                    scopeForConstructor,
                    CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call),
                    NO_EXPECTED_TYPE,
                    DataFlowInfo.EMPTY);
            if (results.isSuccess()) {
              JetType supertype = results.getResultingDescriptor().getReturnType();
              recordSupertype(typeReference, supertype);
              ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
              if (classDescriptor != null) {
                if (classDescriptor.getKind() == ClassKind.TRAIT) {
                  trace.report(CONSTRUCTOR_IN_TRAIT.on(elementToMark));
                }
              }
            } else {
              recordSupertype(
                  typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
            }
          }

          @Override
          public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) {
            JetTypeReference typeReference = specifier.getTypeReference();
            JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
            recordSupertype(typeReference, supertype);
            if (supertype == null) return;
            ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
            if (classDescriptor == null) return;
            if (descriptor.getKind() != ClassKind.TRAIT
                && classDescriptor.hasConstructors()
                && !ErrorUtils.isError(classDescriptor.getTypeConstructor())
                && classDescriptor.getKind() != ClassKind.TRAIT) {
              boolean hasConstructorWithoutParams = false;
              for (ConstructorDescriptor constructor : classDescriptor.getConstructors()) {
                if (constructor.getValueParameters().isEmpty()) {
                  hasConstructorWithoutParams = true;
                }
              }
              if (!hasConstructorWithoutParams) {
                trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier));
              } else {
                trace.report(SUPERTYPE_NOT_INITIALIZED_DEFAULT.on(specifier));
              }
            }
          }

          @Override
          public void visitDelegationToThisCall(JetDelegatorToThisCall thisCall) {
            throw new IllegalStateException("This-calls should be prohibited by the parser");
          }

          @Override
          public void visitJetElement(JetElement element) {
            throw new UnsupportedOperationException(element.getText() + " : " + element);
          }
        };

    for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
      delegationSpecifier.accept(visitor);
    }

    Set<TypeConstructor> parentEnum = Collections.emptySet();
    if (jetClass instanceof JetEnumEntry) {
      parentEnum =
          Collections.singleton(
              ((ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration())
                  .getTypeConstructor());
    }

    checkSupertypeList(descriptor, supertypes, parentEnum);
  }