@NotNull @Override public LightClassConstructionContext getContextForClassOrObject( @NotNull JetClassOrObject classOrObject) { ResolveSessionForBodies session = KotlinCacheService.getInstance(classOrObject.getProject()) .getLazyResolveSession(classOrObject); if (classOrObject.isLocal()) { BindingContext bindingContext = session.resolveToElement(classOrObject, BodyResolveMode.FULL); ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, classOrObject); if (descriptor == null) { LOG.warn( "No class descriptor in context for class: " + PsiUtilPackage.getElementTextWithContext(classOrObject)); return new LightClassConstructionContext(bindingContext, session.getModuleDescriptor()); } ForceResolveUtil.forceResolveAllContents(descriptor); return new LightClassConstructionContext(bindingContext, session.getModuleDescriptor()); } ForceResolveUtil.forceResolveAllContents(session.getClassDescriptor(classOrObject)); return new LightClassConstructionContext( session.getBindingContext(), session.getModuleDescriptor()); }
@NotNull private static PsiClass findCorrespondingLightClass( @NotNull JetClassOrObject decompiledClassOrObject, @NotNull PsiClass rootLightClassForDecompiledFile) { FqName relativeFqName = getClassRelativeName(decompiledClassOrObject); Iterator<Name> iterator = relativeFqName.pathSegments().iterator(); Name base = iterator.next(); assert rootLightClassForDecompiledFile.getName().equals(base.asString()) : "Light class for file:\n" + decompiledClassOrObject.getContainingJetFile().getVirtualFile().getCanonicalPath() + "\nwas expected to have name: " + base.asString() + "\n Actual: " + rootLightClassForDecompiledFile.getName(); PsiClass current = rootLightClassForDecompiledFile; while (iterator.hasNext()) { Name name = iterator.next(); PsiClass innerClass = current.findInnerClassByName(name.asString(), false); assert innerClass != null : "Could not find corresponding inner/nested class " + relativeFqName + " in class " + decompiledClassOrObject.getFqName() + "\n" + "File: " + decompiledClassOrObject.getContainingJetFile().getVirtualFile().getName(); current = innerClass; } return current; }
@NotNull private static FqName getClassRelativeName(@NotNull JetClassOrObject decompiledClassOrObject) { Name name = decompiledClassOrObject.getNameAsName(); assert name != null; JetClassOrObject parent = PsiTreeUtil.getParentOfType(decompiledClassOrObject, JetClassOrObject.class, true); if (parent == null) { assert decompiledClassOrObject.isTopLevel(); return FqName.topLevel(name); } return getClassRelativeName(parent).child(name); }
@Nullable @Override public PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject) { VirtualFile virtualFile = classOrObject.getContainingFile().getVirtualFile(); if (virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, classOrObject.getProject()) != null) { if (ProjectRootsUtil.isLibraryClassFile(project, virtualFile)) { return getLightClassForDecompiledClassOrObject(classOrObject); } return JetSourceNavigationHelper.getOriginalClass(classOrObject); } return KotlinLightClassForExplicitDeclaration.create(psiManager, classOrObject); }
@NotNull private List<JetParameter> getPrimaryConstructorParameters() { if (declaration instanceof JetClass) { return declaration.getPrimaryConstructorParameters(); } return Collections.emptyList(); }
private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) { Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils.buildDeepSubstitutionMultimap(classDescriptor.getDefaultType()); for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) { Collection<TypeProjection> projections = entry.getValue(); if (projections.size() > 1) { TypeConstructor typeConstructor = entry.getKey(); DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor; TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; // Immediate arguments of supertypes cannot be projected Set<JetType> conflictingTypes = Sets.newLinkedHashSet(); for (TypeProjection projection : projections) { conflictingTypes.add(projection.getType()); } removeDuplicateTypes(conflictingTypes); if (conflictingTypes.size() > 1) { DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); assert containingDeclaration instanceof ClassDescriptor : containingDeclaration; JetClassOrObject psiElement = (JetClassOrObject) DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor); assert psiElement != null; JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList(); assert delegationSpecifierList != null; // // trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter // " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " // has inconsistent values: " + conflictingTypes); trace.report( INCONSISTENT_TYPE_PARAMETER_VALUES.on( delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration, conflictingTypes)); } } } }
private void resolvePrimaryConstructorParameters(@NotNull BodiesResolveContext c) { for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) { JetClassOrObject klass = entry.getKey(); ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue(); ConstructorDescriptor unsubstitutedPrimaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); if (unsubstitutedPrimaryConstructor != null) { ForceResolveUtil.forceResolveAllContents(unsubstitutedPrimaryConstructor.getAnnotations()); LexicalScope parameterScope = getPrimaryConstructorParametersScope( classDescriptor.getScopeForClassHeaderResolution(), unsubstitutedPrimaryConstructor); valueParameterResolver.resolveValueParameters( klass.getPrimaryConstructorParameters(), unsubstitutedPrimaryConstructor.getValueParameters(), parameterScope, c.getOuterDataFlowInfo(), trace); } } }
@Nullable private static PsiClass getLightClassForDecompiledClassOrObject( @NotNull JetClassOrObject decompiledClassOrObject) { if (decompiledClassOrObject instanceof JetEnumEntry) { return null; } JetFile containingJetFile = decompiledClassOrObject.getContainingJetFile(); if (!containingJetFile.isCompiled()) { return null; } PsiClass rootLightClassForDecompiledFile = createLightClassForDecompiledKotlinFile(containingJetFile); if (rootLightClassForDecompiledFile == null) return null; return findCorrespondingLightClass(decompiledClassOrObject, rootLightClassForDecompiledFile); }
private void checkTypesInClassHeader(@NotNull JetClassOrObject classOrObject) { for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) { checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference()); } if (!(classOrObject instanceof JetClass)) return; JetClass jetClass = (JetClass) classOrObject; for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) { checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound()); checkFinalUpperBounds(jetTypeParameter.getExtendsBound()); } for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) { checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference()); checkFinalUpperBounds(constraint.getBoundTypeReference()); } }
private void checkPrimaryConstructor( JetClassOrObject classOrObject, ClassDescriptor classDescriptor) { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); JetPrimaryConstructor declaration = classOrObject.getPrimaryConstructor(); if (primaryConstructor == null || declaration == null) return; for (JetParameter parameter : declaration.getValueParameters()) { PropertyDescriptor propertyDescriptor = trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter); if (propertyDescriptor != null) { modifiersChecker.checkModifiersForDeclaration(parameter, propertyDescriptor); } } if (declaration.getModifierList() != null && !declaration.hasConstructorKeyword()) { trace.report(MISSING_CONSTRUCTOR_KEYWORD.on(declaration.getModifierList())); } if (!(classOrObject instanceof JetClass)) { trace.report(CONSTRUCTOR_IN_OBJECT.on(declaration)); } checkConstructorDeclaration(primaryConstructor, declaration); }
private void checkAnnotationClassWithBody(JetClassOrObject classOrObject) { if (classOrObject.getBody() != null) { trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody())); } }
public void resolveDelegationSpecifierList( @NotNull final DataFlowInfo outerDataFlowInfo, @NotNull JetClassOrObject jetClass, @NotNull final ClassDescriptor descriptor, @Nullable final ConstructorDescriptor primaryConstructor, @NotNull LexicalScope scopeForSupertypeResolution, @NotNull final LexicalScope scopeForMemberResolution) { final LexicalScope scopeForConstructor = primaryConstructor == null ? null : FunctionDescriptorUtil.getFunctionInnerScope( scopeForSupertypeResolution, primaryConstructor, trace); final ExpressionTypingServices typeInferrer = expressionTypingServices; // TODO : flow final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap(); final ResolvedCall<?>[] primaryConstructorDelegationCall = new ResolvedCall[1]; JetVisitorVoid visitor = new JetVisitorVoid() { private void recordSupertype(JetTypeReference typeReference, JetType supertype) { if (supertype == null) return; supertypes.put(typeReference, supertype); } @Override public void visitDelegationByExpressionSpecifier( @NotNull JetDelegatorByExpressionSpecifier specifier) { if (descriptor.getKind() == ClassKind.INTERFACE) { 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.INTERFACE) { trace.report(DELEGATION_NOT_TO_TRAIT.on(specifier.getTypeReference())); } } } JetExpression delegateExpression = specifier.getDelegateExpression(); if (delegateExpression != null) { LexicalScope scope = scopeForConstructor == null ? scopeForMemberResolution : scopeForConstructor; JetType expectedType = supertype != null ? supertype : NO_EXPECTED_TYPE; typeInferrer.getType( scope, delegateExpression, expectedType, outerDataFlowInfo, trace); } if (primaryConstructor == null) { trace.report( UNSUPPORTED.on( specifier, "Delegation without primary constructor is not supported")); } } @Override public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); PsiElement elementToMark = valueArgumentList == null ? call : valueArgumentList; if (descriptor.getKind() == ClassKind.INTERFACE) { trace.report(SUPERTYPE_INITIALIZED_IN_TRAIT.on(elementToMark)); } JetTypeReference typeReference = call.getTypeReference(); if (typeReference == null) return; if (primaryConstructor == null) { if (descriptor.getKind() != ClassKind.INTERFACE) { trace.report(SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR.on(call)); } recordSupertype( typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); return; } OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall( trace, scopeForConstructor, CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, outerDataFlowInfo, false); if (results.isSuccess()) { JetType supertype = results.getResultingDescriptor().getReturnType(); recordSupertype(typeReference, supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { // allow only one delegating constructor if (primaryConstructorDelegationCall[0] == null) { primaryConstructorDelegationCall[0] = results.getResultingCall(); } else { primaryConstructorDelegationCall[0] = null; } } // Recording type info for callee to use later in JetObjectLiteralExpression trace.record(PROCESSED, call.getCalleeExpression(), true); trace.record( EXPRESSION_TYPE_INFO, call.getCalleeExpression(), TypeInfoFactoryPackage.noTypeInfo( results.getResultingCall().getDataFlowInfoForArguments().getResultInfo())); } else { recordSupertype( typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); } } @Override public void visitDelegationToSuperClassSpecifier( @NotNull JetDelegatorToSuperClass specifier) { JetTypeReference typeReference = specifier.getTypeReference(); JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); recordSupertype(typeReference, supertype); if (supertype == null) return; ClassDescriptor superClass = TypeUtils.getClassDescriptor(supertype); if (superClass == null) return; if (superClass.getKind().isSingleton()) { // A "singleton in supertype" diagnostic will be reported later return; } if (descriptor.getKind() != ClassKind.INTERFACE && descriptor.getUnsubstitutedPrimaryConstructor() != null && superClass.getKind() != ClassKind.INTERFACE && !superClass.getConstructors().isEmpty() && !ErrorUtils.isError(superClass)) { trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier)); } } @Override public void visitJetElement(@NotNull JetElement element) { throw new UnsupportedOperationException(element.getText() + " : " + element); } }; for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) { delegationSpecifier.accept(visitor); } if (DescriptorUtils.isAnnotationClass(descriptor) && jetClass.getDelegationSpecifierList() != null) { trace.report(SUPERTYPES_FOR_ANNOTATION_CLASS.on(jetClass.getDelegationSpecifierList())); } if (primaryConstructorDelegationCall[0] != null && primaryConstructor != null) { recordConstructorDelegationCall( trace, primaryConstructor, primaryConstructorDelegationCall[0]); } checkSupertypeList(descriptor, supertypes, jetClass); }