From 292cb9baa991f01cca947300e43453fa5c4fa4dc Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 25 Dec 2014 18:17:05 +0300 Subject: [PATCH] Resolve dangling annotations in files and class bodies --- .../jetbrains/jet/lang/psi/JetClassBody.java | 17 +++++++++ .../org/jetbrains/jet/lang/psi/JetFile.java | 17 +++++++++ .../jet/lang/resolve/DeclarationResolver.java | 19 +++++++--- .../jet/lang/resolve/LazyTopDownAnalyzer.java | 36 +++++-------------- .../resolve/lazy/data/JetClassLikeInfo.java | 2 ++ .../lazy/data/JetClassOrObjectInfo.java | 7 ++++ .../lang/resolve/lazy/data/JetScriptInfo.kt | 1 + .../lazy/data/SyntheticClassObjectInfo.java | 6 ++++ .../lazy/descriptors/LazyClassDescriptor.java | 13 +++++++ .../tests/annotations/DanglingMixed.kt | 22 ++++++++++++ .../tests/annotations/DanglingMixed.txt | 23 ++++++++++++ .../tests/annotations/DanglingNoBrackets.kt | 13 +++++++ .../tests/annotations/DanglingNoBrackets.txt | 16 +++++++++ .../tests/annotations/DanglingWithBrackets.kt | 16 +++++++++ .../annotations/DanglingWithBrackets.txt | 17 +++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 18 ++++++++++ 16 files changed, 212 insertions(+), 31 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/annotations/DanglingMixed.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/DanglingMixed.txt create mode 100644 compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.txt create mode 100644 compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassBody.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassBody.java index c7f54d5a48d..d8959832a86 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassBody.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassBody.java @@ -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 getDanglingAnnotations() { + return KotlinPackage.flatMap( + findChildrenByClass(JetModifierList.class), + new Function1>() { + @Override + public Iterable invoke(JetModifierList modifierList) { + return modifierList.getAnnotationEntries(); + } + }); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java index ba6cdd9b1f4..218298fc770 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java @@ -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 getDanglingAnnotations() { + return KotlinPackage.flatMap( + findChildrenByClass(JetModifierList.class), + new Function1>() { + @Override + public Iterable invoke(JetModifierList modifierList) { + return modifierList.getAnnotationEntries(); + } + }); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java index 5bb33de5a45..d9b972aa15d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java @@ -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 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 entry : c.getDeclaredClasses().entrySet()) { JetClassOrObject klass = entry.getKey(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/LazyTopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/LazyTopDownAnalyzer.java index da1240813e0..5802c4baac3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/LazyTopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/LazyTopDownAnalyzer.java @@ -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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetClassLikeInfo.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetClassLikeInfo.java index 1a7eb9484e3..7ac8efd02b8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetClassLikeInfo.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetClassLikeInfo.java @@ -57,4 +57,6 @@ public interface JetClassLikeInfo extends JetDeclarationContainer { @NotNull ClassKind getClassKind(); + @NotNull + List getDanglingAnnotations(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetClassOrObjectInfo.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetClassOrObjectInfo.java index 48b6a97d4b5..328422cd322 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetClassOrObjectInfo.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetClassOrObjectInfo.java @@ -77,6 +77,13 @@ public abstract class JetClassOrObjectInfo implement throw new IllegalArgumentException("Not in a JetFile: " + element); } + @NotNull + @Override + public List getDanglingAnnotations() { + JetClassBody body = element.getBody(); + return body == null ? Collections.emptyList() : body.getDanglingAnnotations(); + } + @Override public String toString() { return "info for " + element.getText(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetScriptInfo.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetScriptInfo.kt index 12536fdfa70..a09ffd797d5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetScriptInfo.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/JetScriptInfo.kt @@ -36,6 +36,7 @@ public class JetScriptInfo( override fun getClassKind() = ClassKind.CLASS override fun getDeclarations() = script.getDeclarations() .filter(::shouldBeScriptClassMember) + override fun getDanglingAnnotations() = listOf() } public fun shouldBeScriptClassMember(declaration: JetDeclaration): Boolean { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/SyntheticClassObjectInfo.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/SyntheticClassObjectInfo.java index bb2670bd2ea..477dc2c2fbc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/SyntheticClassObjectInfo.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/data/SyntheticClassObjectInfo.java @@ -96,6 +96,12 @@ public class SyntheticClassObjectInfo implements JetClassLikeInfo { return ClassKind.CLASS_OBJECT; } + @NotNull + @Override + public List getDanglingAnnotations() { + return Collections.emptyList(); + } + @NotNull @Override public List getDeclarations() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java index 58d2451debf..9a2a456f0ad 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java @@ -95,6 +95,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes private final NotNullLazyValue scopeForMemberDeclarationResolution; private final NotNullLazyValue scopeForPropertyInitializerResolution; + private final NullableLazyValue resolveDanglingAnnotations; + private final NullableLazyValue forceResolveAllContents; public LazyClassDescriptor( @@ -190,6 +192,15 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes return computeScopeForPropertyInitializerResolution(); } }); + this.resolveDanglingAnnotations = storageManager.createNullableLazyValue(new Function0() { + @Override + public Void invoke() { + resolveSession.getAnnotationResolver().resolveAnnotationsWithArguments( + getScopeForMemberDeclarationResolution(), originalClassInfo.getDanglingAnnotations(), resolveSession.getTrace() + ); + return null; + } + }); this.forceResolveAllContents = storageManager.createRecursionTolerantNullableLazyValue(new Function0() { @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(); diff --git a/compiler/testData/diagnostics/tests/annotations/DanglingMixed.kt b/compiler/testData/diagnostics/tests/annotations/DanglingMixed.kt new file mode 100644 index 00000000000..285234d5c68 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/DanglingMixed.kt @@ -0,0 +1,22 @@ +annotation class Ann +annotation class Ann2 + +class C { + fun foo() { + class Local { + Ann0 + [Ann Ann3] + Ann2(1) + [Ann4] + } + } + Ann0 + [Ann Ann3] + Ann2(1) + [Ann4] +} + +Ann0 +[Ann Ann3] +Ann2(1) +[Ann4] \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/DanglingMixed.txt b/compiler/testData/diagnostics/tests/annotations/DanglingMixed.txt new file mode 100644 index 00000000000..f6b20078b1e --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/DanglingMixed.txt @@ -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 +} diff --git a/compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.kt b/compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.kt new file mode 100644 index 00000000000..d9466b6f5f8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.kt @@ -0,0 +1,13 @@ +annotation class Ann + +class C { + fun foo() { + class Local { + Ann + } + } + + Ann +} + +Ann \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.txt b/compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.txt new file mode 100644 index 00000000000..9c246457a26 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/DanglingNoBrackets.txt @@ -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 +} diff --git a/compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.kt b/compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.kt new file mode 100644 index 00000000000..d742c7213f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.kt @@ -0,0 +1,16 @@ +annotation class Ann + +class C { + fun test() { + [Ann] + } + + fun foo() { + class Local { + [Ann] + } + } + [Ann] +} + +[Ann] \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.txt b/compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.txt new file mode 100644 index 00000000000..ecc8869fdd9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/DanglingWithBrackets.txt @@ -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 +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 3025583202e..3e565760a26 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -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");