Tests for objects + delegation specifier resolution + override bindings for objects
This commit is contained in:
@@ -173,15 +173,19 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
);
|
||||
}
|
||||
|
||||
if (element instanceof JetObjectDeclaration) {
|
||||
if (element instanceof JetObjectDeclaration && !(element.getParent() instanceof JetExpression)) {
|
||||
JetObjectDeclaration jetObjectDeclaration = (JetObjectDeclaration) element;
|
||||
|
||||
return new LineMarkerInfo<JetObjectDeclaration>(
|
||||
jetObjectDeclaration, jetObjectDeclaration.getTextOffset(), Icons.ANONYMOUS_CLASS_ICON, Pass.UPDATE_ALL,
|
||||
new Function<JetObjectDeclaration, String>() {
|
||||
@Override
|
||||
public String fun(JetObjectDeclaration jetObjectDeclaration) {
|
||||
ClassDescriptor classDescriptor = bindingContext.getClassDescriptor(jetObjectDeclaration);
|
||||
return DescriptorRenderer.HTML.renderAsObject(classDescriptor);
|
||||
if (classDescriptor != null) {
|
||||
return DescriptorRenderer.HTML.renderAsObject(classDescriptor);
|
||||
}
|
||||
return "<none>";
|
||||
}
|
||||
},
|
||||
new GutterIconNavigationHandler<JetObjectDeclaration>() {
|
||||
|
||||
@@ -29,29 +29,30 @@ import java.util.Collections;
|
||||
*/
|
||||
public class AnalyzingUtils {
|
||||
private final static Key<CachedValue<BindingContext>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
|
||||
private static final Object lock = new Object();
|
||||
|
||||
synchronized // TODO
|
||||
public static BindingContext analyzeFileWithCache(@NotNull final JetFile file) {
|
||||
// TODO : Synchronization?
|
||||
CachedValue<BindingContext> bindingContextCachedValue = file.getUserData(BINDING_CONTEXT);
|
||||
if (bindingContextCachedValue == null) {
|
||||
bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<BindingContext>() {
|
||||
@Override
|
||||
synchronized // TODO : make it more granular
|
||||
public Result<BindingContext> compute() {
|
||||
try {
|
||||
JetNamespace rootNamespace = file.getRootNamespace();
|
||||
BindingContext bindingContext = analyzeNamespace(rootNamespace, JetControlFlowDataTraceFactory.EMPTY);
|
||||
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
BindingTraceContext bindingTraceContext = new BindingTraceContext();
|
||||
bindingTraceContext.getErrorHandler().genericError(file.getNode(), e.getClass().getSimpleName() + ": " + e.getMessage());
|
||||
return new Result<BindingContext>(bindingTraceContext, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
synchronized (lock) {
|
||||
try {
|
||||
JetNamespace rootNamespace = file.getRootNamespace();
|
||||
BindingContext bindingContext = analyzeNamespace(rootNamespace, JetControlFlowDataTraceFactory.EMPTY);
|
||||
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
BindingTraceContext bindingTraceContext = new BindingTraceContext();
|
||||
bindingTraceContext.getErrorHandler().genericError(file.getNode(), e.getClass().getSimpleName() + ": " + e.getMessage());
|
||||
return new Result<BindingContext>(bindingTraceContext, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
@@ -411,15 +411,20 @@ public class TopDownAnalyzer {
|
||||
|
||||
private void bindOverrides() {
|
||||
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
|
||||
MutableClassDescriptor classDescriptor = entry.getValue();
|
||||
// JetClass jetClass = entry.getKey();
|
||||
bindOverridesInAClass(entry.getValue());
|
||||
}
|
||||
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : objects.entrySet()) {
|
||||
bindOverridesInAClass(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
|
||||
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
|
||||
FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype);
|
||||
if (overridden != null) {
|
||||
((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden);
|
||||
}
|
||||
private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) {
|
||||
|
||||
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
|
||||
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
|
||||
FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype);
|
||||
if (overridden != null) {
|
||||
((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -458,74 +463,79 @@ public class TopDownAnalyzer {
|
||||
private void resolveDelegationSpecifierLists() {
|
||||
// TODO : Make sure the same thing is not initialized twice
|
||||
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
|
||||
final JetClass jetClass = entry.getKey();
|
||||
final MutableClassDescriptor descriptor = entry.getValue();
|
||||
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
|
||||
final JetScope scopeForConstructor = primaryConstructor == null
|
||||
? null
|
||||
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
|
||||
final JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
|
||||
resolveDelegationSpecifierList(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : objects.entrySet()) {
|
||||
resolveDelegationSpecifierList(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
|
||||
delegationSpecifier.accept(new JetVisitor() {
|
||||
@Override
|
||||
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
|
||||
JetExpression delegateExpression = specifier.getDelegateExpression();
|
||||
if (delegateExpression != null) {
|
||||
JetScope scope = scopeForConstructor == null ? descriptor.getScopeForMemberResolution() : scopeForConstructor;
|
||||
JetType type = typeInferrer.getType(scope, delegateExpression, false);
|
||||
JetType supertype = trace.getBindingContext().resolveTypeReference(specifier.getTypeReference());
|
||||
if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible?
|
||||
trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) {
|
||||
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
|
||||
final JetScope scopeForConstructor = primaryConstructor == null
|
||||
? null
|
||||
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
|
||||
final JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
|
||||
|
||||
@Override
|
||||
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
|
||||
JetTypeReference typeReference = call.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
if (jetClass.hasPrimaryConstructor()) {
|
||||
typeInferrer.checkConstructorCall(scopeForConstructor, typeReference, call);
|
||||
}
|
||||
else {
|
||||
JetArgumentList valueArgumentList = call.getValueArgumentList();
|
||||
assert valueArgumentList != null;
|
||||
trace.getErrorHandler().genericError(valueArgumentList.getNode(),
|
||||
"Class " + JetPsiUtil.safeName(jetClass.getName()) + " must have a constructor in order to be able to initialize supertypes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) {
|
||||
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
|
||||
delegationSpecifier.accept(new JetVisitor() {
|
||||
@Override
|
||||
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
|
||||
JetExpression delegateExpression = specifier.getDelegateExpression();
|
||||
if (delegateExpression != null) {
|
||||
JetScope scope = scopeForConstructor == null ? descriptor.getScopeForMemberResolution() : scopeForConstructor;
|
||||
JetType type = typeInferrer.getType(scope, delegateExpression, false);
|
||||
JetType supertype = trace.getBindingContext().resolveTypeReference(specifier.getTypeReference());
|
||||
if (supertype != null) {
|
||||
DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||
if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor())) {
|
||||
trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here");
|
||||
}
|
||||
}
|
||||
else {
|
||||
trace.getErrorHandler().genericError(specifier.getNode(), "Only classes may serve as supertypes");
|
||||
}
|
||||
|
||||
if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible?
|
||||
trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDelegationToThisCall(JetDelegatorToThisCall thisCall) {
|
||||
throw new IllegalStateException("This-calls should be prohibited by the parser");
|
||||
@Override
|
||||
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
|
||||
JetTypeReference typeReference = call.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
if (jetClass.hasPrimaryConstructor()) {
|
||||
typeInferrer.checkConstructorCall(scopeForConstructor, typeReference, call);
|
||||
}
|
||||
else {
|
||||
JetArgumentList valueArgumentList = call.getValueArgumentList();
|
||||
assert valueArgumentList != null;
|
||||
trace.getErrorHandler().genericError(valueArgumentList.getNode(),
|
||||
"Class " + JetPsiUtil.safeName(jetClass.getName()) + " must have a constructor in order to be able to initialize supertypes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) {
|
||||
JetType supertype = trace.getBindingContext().resolveTypeReference(specifier.getTypeReference());
|
||||
if (supertype != null) {
|
||||
DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||
if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor())) {
|
||||
trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here");
|
||||
}
|
||||
}
|
||||
else {
|
||||
trace.getErrorHandler().genericError(specifier.getNode(), "Only classes may serve as supertypes");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
throw new UnsupportedOperationException(element.getText() + " : " + element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,7 +698,7 @@ public class TopDownAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
// Top-level properties
|
||||
// Top-level properties & properties of objects
|
||||
for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) {
|
||||
JetProperty property = entry.getKey();
|
||||
if (processed.contains(property)) continue;
|
||||
|
||||
@@ -27,7 +27,9 @@ public class JetStandardLibrary {
|
||||
|
||||
// TODO : consider releasing this memory
|
||||
private static final Map<Project, JetStandardLibrary> standardLibraryCache = new HashMap<Project, JetStandardLibrary>();
|
||||
public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project) {
|
||||
|
||||
// TODO : double checked locking
|
||||
synchronized public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project) {
|
||||
JetStandardLibrary standardLibrary = standardLibraryCache.get(project);
|
||||
if (standardLibrary == null) {
|
||||
standardLibrary = new JetStandardLibrary(project);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
namespace toplevelObjectDeclarations {
|
||||
class Foo(y : Int) {
|
||||
virtual fun foo() : Int = 1
|
||||
}
|
||||
|
||||
class T : <error>Foo</error> {}
|
||||
|
||||
object A : <error>Foo</error> {
|
||||
val x : Int = 2
|
||||
|
||||
fun test() {
|
||||
return x + foo()
|
||||
}
|
||||
}
|
||||
|
||||
object B : <error>A</error> {}
|
||||
|
||||
val x = A.foo()
|
||||
|
||||
val y = object : Foo(x) {
|
||||
{
|
||||
x + 12
|
||||
}
|
||||
|
||||
override fun foo() : Int = 1
|
||||
}
|
||||
|
||||
val z = y.foo()
|
||||
}
|
||||
|
||||
namespace nestedObejcts {
|
||||
object A {
|
||||
val b = B
|
||||
val d = A.B.A
|
||||
|
||||
object B {
|
||||
val a = A
|
||||
val e = B.A
|
||||
|
||||
object A {
|
||||
val a = A
|
||||
val b = B
|
||||
val x = nestedObejcts.A.B.A
|
||||
val y = this<error>@A</error>
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
object B {
|
||||
val b = B
|
||||
val c = A.B
|
||||
}
|
||||
|
||||
val a = A
|
||||
val b = B
|
||||
val c = A.B
|
||||
val d = A.B.A
|
||||
val e = B.<error>A</error>.B
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
~ns~namespace nestedObjects {
|
||||
object ~A~A {
|
||||
val b = `A.B`B
|
||||
val d = `A`A.`A.B`B.`A.B.A`A
|
||||
|
||||
object ~A.B~B {
|
||||
val a = `A.B.A`A
|
||||
val e = `A.B`B.`A.B.A`A
|
||||
|
||||
object ~A.B.A~A {
|
||||
val a = `A.B.A`A
|
||||
val b = `A.B`B
|
||||
val x = `ns`nestedObjects.`A`A.`A.B`B.`A.B.A`A
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
object ~B~B {
|
||||
val b = `B`B
|
||||
val c = `A`A.`A.B`B
|
||||
}
|
||||
|
||||
val a = `A`A
|
||||
val b = `B`B
|
||||
val c = `A`A.`A.B`B
|
||||
val d = A.B.`A.B.A`A
|
||||
val e = B.`!`A.B
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace toplevelObjectDeclarations {
|
||||
class Foo(y : Int) {
|
||||
~foo()~virtual fun foo() : Int = 1
|
||||
}
|
||||
|
||||
object ~A~A : Foo(0) {
|
||||
~x~val x : Int = 2
|
||||
|
||||
fun test() {
|
||||
return `x`x + `foo()`foo()
|
||||
}
|
||||
}
|
||||
|
||||
object B : `!`A {}
|
||||
|
||||
~ns.x~val x = `A`A.`foo()`foo()
|
||||
|
||||
~y~val y = object : Foo(`ns.x`x) {
|
||||
{
|
||||
`ns.x`x + 12
|
||||
}
|
||||
|
||||
~y.foo()~override fun foo() : Int = 1
|
||||
}
|
||||
|
||||
val z = `y`y.`y.foo()`foo()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user