Resolve dangling annotations in files and class bodies

This commit is contained in:
Andrey Breslav
2014-12-25 18:17:05 +03:00
parent e296390dd6
commit 292cb9baa9
16 changed files with 212 additions and 31 deletions
@@ -19,6 +19,8 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.TokenSet; import com.intellij.psi.tree.TokenSet;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.JetNodeTypes;
@@ -83,4 +85,19 @@ public class JetClassBody extends JetElementImplStub<KotlinPlaceHolderStub<JetCl
ASTNode[] children = getNode().getChildren(TokenSet.create(JetTokens.LBRACE)); ASTNode[] children = getNode().getChildren(TokenSet.create(JetTokens.LBRACE));
return children.length == 1 ? children[0].getPsi() : null; return children.length == 1 ? children[0].getPsi() : null;
} }
/**
* @return annotations that do not belong to any declaration due to incomplete code or syntax errors
*/
@NotNull
public List<JetAnnotationEntry> getDanglingAnnotations() {
return KotlinPackage.flatMap(
findChildrenByClass(JetModifierList.class),
new Function1<JetModifierList, Iterable<JetAnnotationEntry>>() {
@Override
public Iterable<JetAnnotationEntry> invoke(JetModifierList modifierList) {
return modifierList.getAnnotationEntries();
}
});
}
} }
@@ -26,6 +26,8 @@ import com.intellij.psi.PsiClassOwner;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.JetNodeTypes;
@@ -237,4 +239,19 @@ public class JetFile extends PsiFileBase implements JetDeclarationContainer, Jet
return fileAnnotationList.getAnnotationEntries(); return fileAnnotationList.getAnnotationEntries();
} }
/**
* @return annotations that do not belong to any declaration due to incomplete code or syntax errors
*/
@NotNull
public List<JetAnnotationEntry> getDanglingAnnotations() {
return KotlinPackage.flatMap(
findChildrenByClass(JetModifierList.class),
new Function1<JetModifierList, Iterable<JetAnnotationEntry>>() {
@Override
public Iterable<JetAnnotationEntry> invoke(JetModifierList modifierList) {
return modifierList.getAnnotationEntries();
}
});
}
} }
@@ -51,13 +51,9 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.REDECLARATION;
import static org.jetbrains.jet.lang.resolve.ScriptHeaderResolver.resolveScriptDeclarations; import static org.jetbrains.jet.lang.resolve.ScriptHeaderResolver.resolveScriptDeclarations;
public class DeclarationResolver { public class DeclarationResolver {
@NotNull
private AnnotationResolver annotationResolver; private AnnotationResolver annotationResolver;
@NotNull
private ImportsResolver importsResolver; private ImportsResolver importsResolver;
@NotNull
private DescriptorResolver descriptorResolver; private DescriptorResolver descriptorResolver;
@NotNull
private BindingTrace trace; private BindingTrace trace;
@@ -87,6 +83,7 @@ public class DeclarationResolver {
resolveConstructorHeaders(c); resolveConstructorHeaders(c);
resolveAnnotationStubsOnClassesAndConstructors(c); resolveAnnotationStubsOnClassesAndConstructors(c);
resolveFunctionAndPropertyHeaders(c); resolveFunctionAndPropertyHeaders(c);
resolveDanglingAnnotationsInClasses(c);
resolveAnnotationsOnFiles(c.getFileScopes()); resolveAnnotationsOnFiles(c.getFileScopes());
// SCRIPT: Resolve script declarations // SCRIPT: Resolve script declarations
@@ -115,6 +112,7 @@ public class DeclarationResolver {
JetFile file = entry.getKey(); JetFile file = entry.getKey();
JetScope fileScope = entry.getValue(); JetScope fileScope = entry.getValue();
annotationResolver.resolveAnnotationsWithArguments(fileScope, file.getAnnotationEntries(), trace); annotationResolver.resolveAnnotationsWithArguments(fileScope, file.getAnnotationEntries(), trace);
annotationResolver.resolveAnnotationsWithArguments(fileScope, file.getDanglingAnnotations(), trace);
} }
} }
@@ -222,6 +220,19 @@ public class DeclarationResolver {
} }
} }
private void resolveDanglingAnnotationsInClasses(TopDownAnalysisContext c) {
for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
JetClassBody body = entry.getKey().getBody();
if (body != null) {
annotationResolver.resolveAnnotationsWithArguments(
entry.getValue().getScopeForMemberDeclarationResolution(),
body.getDanglingAnnotations(),
trace
);
}
}
}
private void createFunctionsForDataClasses(@NotNull TopDownAnalysisContext c) { private void createFunctionsForDataClasses(@NotNull TopDownAnalysisContext c) {
for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) { for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
JetClassOrObject klass = entry.getKey(); JetClassOrObject klass = entry.getKey();
@@ -44,41 +44,23 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_CLASS_OBJECTS;
import static org.jetbrains.jet.lang.diagnostics.Errors.UNSUPPORTED; import static org.jetbrains.jet.lang.diagnostics.Errors.UNSUPPORTED;
public class LazyTopDownAnalyzer { public class LazyTopDownAnalyzer {
@SuppressWarnings("ConstantConditions") private BindingTrace trace;
@NotNull
private BindingTrace trace = null;
@SuppressWarnings("ConstantConditions") private DeclarationResolver declarationResolver;
@NotNull
private DeclarationResolver declarationResolver = null;
@SuppressWarnings("ConstantConditions") private OverrideResolver overrideResolver;
@NotNull
private OverrideResolver overrideResolver = null;
@SuppressWarnings("ConstantConditions") private OverloadResolver overloadResolver;
@NotNull
private OverloadResolver overloadResolver = null;
@SuppressWarnings("ConstantConditions") private VarianceChecker varianceChecker;
@NotNull
private VarianceChecker varianceChecker = null;
@SuppressWarnings("ConstantConditions") private ModuleDescriptor moduleDescriptor;
@NotNull
private ModuleDescriptor moduleDescriptor = null;
@SuppressWarnings("ConstantConditions") private KotlinCodeAnalyzer resolveSession;
@NotNull
private KotlinCodeAnalyzer resolveSession = null;
@SuppressWarnings("ConstantConditions") private BodyResolver bodyResolver;
@NotNull
private BodyResolver bodyResolver = null;
@SuppressWarnings("ConstantConditions") private TopDownAnalyzer topDownAnalyzer;
@NotNull
private TopDownAnalyzer topDownAnalyzer = null;
@Inject @Inject
public void setKotlinCodeAnalyzer(@NotNull KotlinCodeAnalyzer kotlinCodeAnalyzer) { public void setKotlinCodeAnalyzer(@NotNull KotlinCodeAnalyzer kotlinCodeAnalyzer) {
@@ -57,4 +57,6 @@ public interface JetClassLikeInfo extends JetDeclarationContainer {
@NotNull @NotNull
ClassKind getClassKind(); ClassKind getClassKind();
@NotNull
List<JetAnnotationEntry> getDanglingAnnotations();
} }
@@ -77,6 +77,13 @@ public abstract class JetClassOrObjectInfo<E extends JetClassOrObject> implement
throw new IllegalArgumentException("Not in a JetFile: " + element); throw new IllegalArgumentException("Not in a JetFile: " + element);
} }
@NotNull
@Override
public List<JetAnnotationEntry> getDanglingAnnotations() {
JetClassBody body = element.getBody();
return body == null ? Collections.<JetAnnotationEntry>emptyList() : body.getDanglingAnnotations();
}
@Override @Override
public String toString() { public String toString() {
return "info for " + element.getText(); return "info for " + element.getText();
@@ -36,6 +36,7 @@ public class JetScriptInfo(
override fun getClassKind() = ClassKind.CLASS override fun getClassKind() = ClassKind.CLASS
override fun getDeclarations() = script.getDeclarations() override fun getDeclarations() = script.getDeclarations()
.filter(::shouldBeScriptClassMember) .filter(::shouldBeScriptClassMember)
override fun getDanglingAnnotations() = listOf<JetAnnotationEntry>()
} }
public fun shouldBeScriptClassMember(declaration: JetDeclaration): Boolean { public fun shouldBeScriptClassMember(declaration: JetDeclaration): Boolean {
@@ -96,6 +96,12 @@ public class SyntheticClassObjectInfo implements JetClassLikeInfo {
return ClassKind.CLASS_OBJECT; return ClassKind.CLASS_OBJECT;
} }
@NotNull
@Override
public List<JetAnnotationEntry> getDanglingAnnotations() {
return Collections.emptyList();
}
@NotNull @NotNull
@Override @Override
public List<JetDeclaration> getDeclarations() { public List<JetDeclaration> getDeclarations() {
@@ -95,6 +95,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
private final NotNullLazyValue<JetScope> scopeForMemberDeclarationResolution; private final NotNullLazyValue<JetScope> scopeForMemberDeclarationResolution;
private final NotNullLazyValue<JetScope> scopeForPropertyInitializerResolution; private final NotNullLazyValue<JetScope> scopeForPropertyInitializerResolution;
private final NullableLazyValue<Void> resolveDanglingAnnotations;
private final NullableLazyValue<Void> forceResolveAllContents; private final NullableLazyValue<Void> forceResolveAllContents;
public LazyClassDescriptor( public LazyClassDescriptor(
@@ -190,6 +192,15 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
return computeScopeForPropertyInitializerResolution(); return computeScopeForPropertyInitializerResolution();
} }
}); });
this.resolveDanglingAnnotations = storageManager.createNullableLazyValue(new Function0<Void>() {
@Override
public Void invoke() {
resolveSession.getAnnotationResolver().resolveAnnotationsWithArguments(
getScopeForMemberDeclarationResolution(), originalClassInfo.getDanglingAnnotations(), resolveSession.getTrace()
);
return null;
}
});
this.forceResolveAllContents = storageManager.createRecursionTolerantNullableLazyValue(new Function0<Void>() { this.forceResolveAllContents = storageManager.createRecursionTolerantNullableLazyValue(new Function0<Void>() {
@Override @Override
public Void invoke() { public Void invoke() {
@@ -448,6 +459,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
public void resolveMemberHeaders() { public void resolveMemberHeaders() {
ForceResolveUtil.forceResolveAllContents(getAnnotations()); ForceResolveUtil.forceResolveAllContents(getAnnotations());
resolveDanglingAnnotations.invoke();
getClassObjectDescriptor(); getClassObjectDescriptor();
getDescriptorsForExtraClassObjects(); getDescriptorsForExtraClassObjects();
@@ -0,0 +1,22 @@
annotation class Ann
annotation class Ann2
class C {
fun foo() {
class Local {
<!UNRESOLVED_REFERENCE!>Ann0<!>
[Ann <!UNRESOLVED_REFERENCE!>Ann3<!>]
Ann2(<!TOO_MANY_ARGUMENTS!>1<!>)
[<!UNRESOLVED_REFERENCE!>Ann4<!>]<!SYNTAX!><!>
}
}
<!UNRESOLVED_REFERENCE!>Ann0<!>
[Ann <!UNRESOLVED_REFERENCE!>Ann3<!>]
Ann2(<!TOO_MANY_ARGUMENTS!>1<!>)
[<!UNRESOLVED_REFERENCE!>Ann4<!>]<!SYNTAX!><!>
}
<!UNRESOLVED_REFERENCE!>Ann0<!>
[Ann <!UNRESOLVED_REFERENCE!>Ann3<!>]
Ann2(<!TOO_MANY_ARGUMENTS!>1<!>)
[<!UNRESOLVED_REFERENCE!>Ann4<!>]<!SYNTAX!><!>
@@ -0,0 +1,23 @@
package
internal final annotation class Ann : kotlin.Annotation {
public constructor Ann()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final annotation class Ann2 : kotlin.Annotation {
public constructor Ann2()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
internal final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,13 @@
annotation class Ann
class C {
fun foo() {
class Local {
Ann<!SYNTAX!><!>
}
}
Ann<!SYNTAX!><!>
}
Ann<!SYNTAX!><!>
@@ -0,0 +1,16 @@
package
internal final annotation class Ann : kotlin.Annotation {
public constructor Ann()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
internal final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,16 @@
annotation class Ann
class C {
fun test() {
[Ann]<!SYNTAX!><!>
}
fun foo() {
class Local {
[Ann]<!SYNTAX!><!>
}
}
[Ann]<!SYNTAX!><!>
}
[Ann]<!SYNTAX!><!>
@@ -0,0 +1,17 @@
package
internal final annotation class Ann : kotlin.Annotation {
public constructor Ann()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
internal final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
internal final fun test(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -637,6 +637,24 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("DanglingMixed.kt")
public void testDanglingMixed() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/DanglingMixed.kt");
doTest(fileName);
}
@TestMetadata("DanglingNoBrackets.kt")
public void testDanglingNoBrackets() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.kt");
doTest(fileName);
}
@TestMetadata("DanglingWithBrackets.kt")
public void testDanglingWithBrackets() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.kt");
doTest(fileName);
}
@TestMetadata("Deprecated.kt") @TestMetadata("Deprecated.kt")
public void testDeprecated() throws Exception { public void testDeprecated() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/Deprecated.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");