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.psi.PsiElement;
import com.intellij.psi.tree.TokenSet;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
@@ -83,4 +85,19 @@ public class JetClassBody extends JetElementImplStub<KotlinPlaceHolderStub<JetCl
ASTNode[] children = getNode().getChildren(TokenSet.create(JetTokens.LBRACE));
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.stubs.StubElement;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
@@ -237,4 +239,19 @@ public class JetFile extends PsiFileBase implements JetDeclarationContainer, Jet
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;
public class DeclarationResolver {
@NotNull
private AnnotationResolver annotationResolver;
@NotNull
private ImportsResolver importsResolver;
@NotNull
private DescriptorResolver descriptorResolver;
@NotNull
private BindingTrace trace;
@@ -87,6 +83,7 @@ public class DeclarationResolver {
resolveConstructorHeaders(c);
resolveAnnotationStubsOnClassesAndConstructors(c);
resolveFunctionAndPropertyHeaders(c);
resolveDanglingAnnotationsInClasses(c);
resolveAnnotationsOnFiles(c.getFileScopes());
// SCRIPT: Resolve script declarations
@@ -115,6 +112,7 @@ public class DeclarationResolver {
JetFile file = entry.getKey();
JetScope fileScope = entry.getValue();
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) {
for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
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;
public class LazyTopDownAnalyzer {
@SuppressWarnings("ConstantConditions")
@NotNull
private BindingTrace trace = null;
private BindingTrace trace;
@SuppressWarnings("ConstantConditions")
@NotNull
private DeclarationResolver declarationResolver = null;
private DeclarationResolver declarationResolver;
@SuppressWarnings("ConstantConditions")
@NotNull
private OverrideResolver overrideResolver = null;
private OverrideResolver overrideResolver;
@SuppressWarnings("ConstantConditions")
@NotNull
private OverloadResolver overloadResolver = null;
private OverloadResolver overloadResolver;
@SuppressWarnings("ConstantConditions")
@NotNull
private VarianceChecker varianceChecker = null;
private VarianceChecker varianceChecker;
@SuppressWarnings("ConstantConditions")
@NotNull
private ModuleDescriptor moduleDescriptor = null;
private ModuleDescriptor moduleDescriptor;
@SuppressWarnings("ConstantConditions")
@NotNull
private KotlinCodeAnalyzer resolveSession = null;
private KotlinCodeAnalyzer resolveSession;
@SuppressWarnings("ConstantConditions")
@NotNull
private BodyResolver bodyResolver = null;
private BodyResolver bodyResolver;
@SuppressWarnings("ConstantConditions")
@NotNull
private TopDownAnalyzer topDownAnalyzer = null;
private TopDownAnalyzer topDownAnalyzer;
@Inject
public void setKotlinCodeAnalyzer(@NotNull KotlinCodeAnalyzer kotlinCodeAnalyzer) {
@@ -57,4 +57,6 @@ public interface JetClassLikeInfo extends JetDeclarationContainer {
@NotNull
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);
}
@NotNull
@Override
public List<JetAnnotationEntry> getDanglingAnnotations() {
JetClassBody body = element.getBody();
return body == null ? Collections.<JetAnnotationEntry>emptyList() : body.getDanglingAnnotations();
}
@Override
public String toString() {
return "info for " + element.getText();
@@ -36,6 +36,7 @@ public class JetScriptInfo(
override fun getClassKind() = ClassKind.CLASS
override fun getDeclarations() = script.getDeclarations()
.filter(::shouldBeScriptClassMember)
override fun getDanglingAnnotations() = listOf<JetAnnotationEntry>()
}
public fun shouldBeScriptClassMember(declaration: JetDeclaration): Boolean {
@@ -96,6 +96,12 @@ public class SyntheticClassObjectInfo implements JetClassLikeInfo {
return ClassKind.CLASS_OBJECT;
}
@NotNull
@Override
public List<JetAnnotationEntry> getDanglingAnnotations() {
return Collections.emptyList();
}
@NotNull
@Override
public List<JetDeclaration> getDeclarations() {
@@ -95,6 +95,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
private final NotNullLazyValue<JetScope> scopeForMemberDeclarationResolution;
private final NotNullLazyValue<JetScope> scopeForPropertyInitializerResolution;
private final NullableLazyValue<Void> resolveDanglingAnnotations;
private final NullableLazyValue<Void> forceResolveAllContents;
public LazyClassDescriptor(
@@ -190,6 +192,15 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
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>() {
@Override
public Void invoke() {
@@ -448,6 +459,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
public void resolveMemberHeaders() {
ForceResolveUtil.forceResolveAllContents(getAnnotations());
resolveDanglingAnnotations.invoke();
getClassObjectDescriptor();
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);
}
@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")
public void testDeprecated() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");