Support @field: annotations

This commit is contained in:
Yan Zhulanow
2015-07-16 16:38:08 +03:00
parent 0499335c34
commit 2bacbc9046
34 changed files with 431 additions and 67 deletions
@@ -81,17 +81,30 @@ public abstract class AnnotationCodegen {
* @param returnType can be null if not applicable (e.g. {@code annotated} is a class)
*/
public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType) {
if (annotated == null) {
return;
}
genAnnotations(annotated, returnType, null);
}
if (!(annotated instanceof DeclarationDescriptor)) {
public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType, @Nullable AnnotationUseSiteTarget target) {
if (annotated == null) {
return;
}
Set<String> annotationDescriptorsAlreadyPresent = new HashSet<String>();
for (AnnotationDescriptor annotation : annotated.getAnnotations()) {
Annotations annotations = annotated.getAnnotations();
if (target != null) {
for (AnnotationWithTarget annotationWithTarget : annotations.getUseSiteTargetedAnnotations()) {
if (target != annotationWithTarget.getTarget()) continue;
String descriptor = genAnnotation(annotationWithTarget.getAnnotation());
if (descriptor != null) {
annotationDescriptorsAlreadyPresent.add(descriptor);
}
}
}
for (AnnotationDescriptor annotation : annotations) {
String descriptor = genAnnotation(annotation);
if (descriptor != null) {
annotationDescriptorsAlreadyPresent.add(descriptor);
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
@@ -293,7 +294,7 @@ public class PropertyCodegen {
FieldVisitor fv = builder.newField(OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(),
typeMapper.mapFieldSignature(jetType), defaultValue);
AnnotationCodegen.forField(fv, typeMapper).genAnnotations(propertyDescriptor, type);
AnnotationCodegen.forField(fv, typeMapper).genAnnotations(propertyDescriptor, type, AnnotationUseSiteTarget.FIELD);
}
private void generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor) {
@@ -58,6 +58,7 @@ public interface JetNodeTypes {
IElementType MODIFIER_LIST = JetStubElementTypes.MODIFIER_LIST;
IElementType ANNOTATION = JetStubElementTypes.ANNOTATION;
IElementType ANNOTATION_ENTRY = JetStubElementTypes.ANNOTATION_ENTRY;
IElementType ANNOTATION_TARGET = JetStubElementTypes.ANNOTATION_TARGET;
IElementType TYPE_ARGUMENT_LIST = JetStubElementTypes.TYPE_ARGUMENT_LIST;
JetNodeType VALUE_ARGUMENT_LIST = new JetNodeType("VALUE_ARGUMENT_LIST", JetValueArgumentList.class);
@@ -131,6 +131,9 @@ public interface Errors {
DiagnosticFactory0<JetExpression> ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetExpression> ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_FIELD_TARGET = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD = DiagnosticFactory0.create(ERROR);
// Classes and traits
DiagnosticFactory0<JetTypeProjection> PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE =
@@ -124,6 +124,9 @@ public class DefaultErrorMessages {
MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING);
MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable");
MAP.put(INAPPLICABLE_FIELD_TARGET, "''@field:'' annotations could be applied only to property declarations");
MAP.put(INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD, "Property has neither a backing field nor a delegate");
MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING);
MAP.put(ABSTRACT_MODIFIER_IN_TRAIT, "Modifier ''abstract'' is redundant in interface");
MAP.put(REDUNDANT_MODIFIER_IN_GETTER, "Visibility modifiers are redundant in getter");
@@ -133,6 +133,7 @@ public interface JetTokens {
JetToken EOL_OR_SEMICOLON = new JetToken("EOL_OR_SEMICOLON");
JetKeywordToken FILE_KEYWORD = JetKeywordToken.softKeyword("file");
JetKeywordToken FIELD_KEYWORD = JetKeywordToken.softKeyword("field");
JetKeywordToken IMPORT_KEYWORD = JetKeywordToken.softKeyword("import");
JetKeywordToken WHERE_KEYWORD = JetKeywordToken.softKeyword("where");
JetKeywordToken BY_KEYWORD = JetKeywordToken.softKeyword("by");
@@ -174,7 +175,8 @@ public interface JetTokens {
SET_KEYWORD, ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, INNER_KEYWORD,
OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD,
CATCH_KEYWORD, FINALLY_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, REIFIED_KEYWORD,
DYNAMIC_KEYWORD, COMPANION_KEYWORD, CONSTRUCTOR_KEYWORD, INIT_KEYWORD, SEALED_KEYWORD
DYNAMIC_KEYWORD, COMPANION_KEYWORD, CONSTRUCTOR_KEYWORD, INIT_KEYWORD, SEALED_KEYWORD,
FIELD_KEYWORD
);
/*
@@ -64,6 +64,7 @@ public class JetParsing extends AbstractJetParsing {
private static final TokenSet LAMBDA_VALUE_PARAMETER_FIRST =
TokenSet.orSet(TokenSet.create(IDENTIFIER, LBRACKET), MODIFIER_KEYWORDS);
private static final TokenSet SOFT_KEYWORDS_AT_MEMBER_START = TokenSet.create(CONSTRUCTOR_KEYWORD, INIT_KEYWORD);
private static final TokenSet ANNOTATION_TARGETS = TokenSet.create(FILE_KEYWORD, FIELD_KEYWORD);
static JetParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) {
JetParsing jetParsing = new JetParsing(builder);
@@ -544,7 +545,7 @@ public class JetParsing extends AbstractJetParsing {
* ;
*
* annotationPrefix:
* : ("@" (":" "file")?)
* : ("@" (":" ("file" | "field"))?)
* ;
*/
private boolean parseAnnotationOrList(AnnotationParsingMode mode) {
@@ -556,7 +557,7 @@ public class JetParsing extends AbstractJetParsing {
IElementType tokenToMatch = nextRawToken;
boolean isTargetedAnnotation = false;
if ((nextRawToken == IDENTIFIER || nextRawToken == FILE_KEYWORD) && lookahead(2) == COLON) {
if ((nextRawToken == IDENTIFIER || ANNOTATION_TARGETS.contains(nextRawToken)) && lookahead(2) == COLON) {
tokenToMatch = lookahead(3);
isTargetedAnnotation = true;
}
@@ -578,7 +579,7 @@ public class JetParsing extends AbstractJetParsing {
errorAndAdvance("Expected annotation identifier after ':'", 2); // AT, COLON
}
else {
errorAndAdvance("Expected annotation identifier after '@file:'", 3); // AT, FILE_KEYWORD, COLON
errorAndAdvance("Expected annotation identifier after ':'", 3); // AT, (ANNOTATION TARGET KEYWORD), COLON
}
}
else {
@@ -634,7 +635,7 @@ public class JetParsing extends AbstractJetParsing {
// Returns true if we should continue parse annotation
private boolean parseAnnotationTargetIfNeeded(AnnotationParsingMode mode) {
String expectedAnnotationTargetBeforeColon = "Expected 'file' keyword before ':'";
String expectedAnnotationTargetBeforeColon = "Expected annotation target before ':'";
if (at(COLON)) {
// recovery for "@:ann"
@@ -666,19 +667,29 @@ public class JetParsing extends AbstractJetParsing {
private void parseAnnotationTarget(AnnotationParsingMode mode, JetKeywordToken keyword) {
if (keyword == FILE_KEYWORD && !mode.isFileAnnotationParsingMode && at(keyword) && lookahead(1) == COLON) {
errorAndAdvance("File annotations are only allowed before package declaration", 2);
errorAndAdvance(AT.getValue() + keyword.getValue() + " annotations are only allowed before package declaration", 2);
return;
}
String message = "Expecting \"" + keyword.getValue() + COLON.getValue() + "\" prefix for " + keyword.getValue() + " annotations";
expect(keyword, message);
PsiBuilder.Marker marker = mark();
if (!expect(keyword, message)) {
marker.drop();
}
else {
marker.done(ANNOTATION_TARGET);
}
expect(COLON, message, TokenSet.create(IDENTIFIER, RBRACKET, LBRACKET));
}
@Nullable
private JetKeywordToken atTargetKeyword() {
if (at(FILE_KEYWORD)) return (JetKeywordToken) FILE_KEYWORD;
for (IElementType target : ANNOTATION_TARGETS.getTypes()) {
if (at(target)) return (JetKeywordToken) target;
}
return null;
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes;
@@ -41,4 +42,9 @@ public class JetAnnotation extends JetElementImplStub<KotlinPlaceHolderStub<JetA
public List<JetAnnotationEntry> getEntries() {
return getStubOrPsiChildrenAsList(JetStubElementTypes.ANNOTATION_ENTRY);
}
@Nullable
public JetAnnotationUseSiteTarget getUseSiteTarget() {
return getStubOrPsiChild(JetStubElementTypes.ANNOTATION_TARGET);
}
}
@@ -107,4 +107,18 @@ public class JetAnnotationEntry extends JetElementImplStub<KotlinAnnotationEntry
public PsiElement getAtSymbol() {
return findChildByType(JetTokens.AT);
}
@Nullable
public JetAnnotationUseSiteTarget getUseSiteTarget() {
JetAnnotationUseSiteTarget target = getStubOrPsiChild(JetStubElementTypes.ANNOTATION_TARGET);
if (target == null) {
PsiElement parent = getStubOrPsiParent();
if (parent instanceof JetAnnotation) {
return ((JetAnnotation) parent).getUseSiteTarget();
}
}
return target;
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.psi
import com.intellij.lang.ASTNode
import com.intellij.psi.impl.source.tree.TreeElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.lexer.JetKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationEntryStub
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub
import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes
public class JetAnnotationUseSiteTarget : JetElementImplStub<KotlinPlaceHolderStub<JetAnnotationUseSiteTarget>> {
constructor(node: ASTNode) : super(node)
constructor(stub: KotlinPlaceHolderStub<JetAnnotationUseSiteTarget>) : super(stub, JetStubElementTypes.ANNOTATION_TARGET)
override fun <R, D> accept(visitor: JetVisitor<R, D>, data: D) = visitor.visitAnnotationUseSiteTarget(this, data)
public fun getAnnotationUseSiteTarget(): AnnotationUseSiteTarget {
val node = getFirstChild().getNode()
return when (node.getElementType()) {
JetTokens.FIELD_KEYWORD -> AnnotationUseSiteTarget.FIELD
JetTokens.FILE_KEYWORD -> AnnotationUseSiteTarget.FILE
else -> throw IllegalStateException("Unknown annotation target " + node.getText())
}
}
}
@@ -106,6 +106,10 @@ public class JetVisitor<R, D> extends PsiElementVisitor {
return visitJetElement(annotationEntry, data);
}
public R visitAnnotationUseSiteTarget(@NotNull JetAnnotationUseSiteTarget annotationTarget, D data) {
return visitJetElement(annotationTarget, data);
}
public R visitConstructorCalleeExpression(@NotNull JetConstructorCalleeExpression constructorCalleeExpression, D data) {
return visitJetElement(constructorCalleeExpression, data);
}
@@ -50,6 +50,9 @@ public interface JetStubElementTypes {
JetPlaceHolderStubElementType<JetAnnotation> ANNOTATION =
new JetPlaceHolderStubElementType<JetAnnotation>("ANNOTATION", JetAnnotation.class);
JetPlaceHolderStubElementType<JetAnnotationUseSiteTarget> ANNOTATION_TARGET =
new JetPlaceHolderStubElementType<JetAnnotationUseSiteTarget>("ANNOTATION_TARGET", JetAnnotationUseSiteTarget.class);
JetPlaceHolderStubElementType<JetClassBody> CLASS_BODY =
new JetPlaceHolderStubElementType<JetClassBody>("CLASS_BODY", JetClassBody.class);
@@ -21,13 +21,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.psi.JetAnnotationEntry;
import org.jetbrains.kotlin.psi.JetModifierList;
import org.jetbrains.kotlin.psi.JetTypeParameter;
import org.jetbrains.kotlin.psi.JetTypeReference;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.CallResolver;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
@@ -45,6 +43,8 @@ import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.JetType;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.jetbrains.kotlin.diagnostics.Errors.NOT_AN_ANNOTATION_CLASS;
@@ -130,7 +130,8 @@ public class AnnotationResolver {
boolean shouldResolveArguments
) {
if (annotationEntryElements.isEmpty()) return Annotations.EMPTY;
List<AnnotationDescriptor> result = Lists.newArrayList();
List<AnnotationWithTarget> result = new ArrayList<AnnotationWithTarget>(0);
for (JetAnnotationEntry entryElement : annotationEntryElements) {
AnnotationDescriptor descriptor = trace.get(BindingContext.ANNOTATION, entryElement);
if (descriptor == null) {
@@ -140,9 +141,15 @@ public class AnnotationResolver {
ForceResolveUtil.forceResolveAllContents(descriptor);
}
result.add(descriptor);
JetAnnotationUseSiteTarget target = entryElement.getUseSiteTarget();
if (target != null) {
result.add(new AnnotationWithTarget(descriptor, target.getAnnotationUseSiteTarget()));
}
else {
result.add(new AnnotationWithTarget(descriptor, null));
}
}
return new AnnotationsImpl(result);
return AnnotationsImpl.create(result);
}
@NotNull
@@ -23,6 +23,10 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
import org.jetbrains.kotlin.lexer.JetKeywordToken;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
@@ -34,6 +38,9 @@ import java.util.*;
import static org.jetbrains.kotlin.diagnostics.Errors.NESTED_CLASS_NOT_ALLOWED;
import static org.jetbrains.kotlin.lexer.JetTokens.*;
import static org.jetbrains.kotlin.psi.JetStubbedPsiUtil.getContainingDeclaration;
import static org.jetbrains.kotlin.resolve.BindingContext.BACKING_FIELD_REQUIRED;
import static org.jetbrains.kotlin.diagnostics.Errors.INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD;
import static org.jetbrains.kotlin.diagnostics.Errors.INAPPLICABLE_FIELD_TARGET;
public class ModifiersChecker {
private static final Collection<JetModifierKeywordToken> MODALITY_MODIFIERS =
@@ -183,6 +190,7 @@ public class ModifiersChecker {
checkNestedClassAllowed(modifierListOwner, descriptor);
ModifierCheckerCore.INSTANCE$.check(modifierListOwner, trace, descriptor);
checkTypeParametersModifiers(modifierListOwner);
checkAnnotationUseSiteTargetApplicability(modifierListOwner, descriptor);
runDeclarationCheckers(modifierListOwner, descriptor);
ClassDescriptor classDescriptor = descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null;
annotationChecker.check(modifierListOwner, trace, classDescriptor);
@@ -192,6 +200,7 @@ public class ModifiersChecker {
@NotNull JetDeclaration modifierListOwner,
@NotNull DeclarationDescriptor descriptor
) {
checkAnnotationUseSiteTargetApplicability(modifierListOwner, descriptor);
runDeclarationCheckers(modifierListOwner, descriptor);
annotationChecker.check(modifierListOwner, trace,
descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null);
@@ -209,6 +218,59 @@ public class ModifiersChecker {
}
}
private void checkAnnotationUseSiteTargetApplicability(
@NotNull JetDeclaration modifierListOwner,
@NotNull DeclarationDescriptor descriptor
) {
for (AnnotationWithTarget annotationWithTarget : descriptor.getAnnotations().getUseSiteTargetedAnnotations()) {
AnnotationDescriptor annotation = annotationWithTarget.getAnnotation();
AnnotationUseSiteTarget target = annotationWithTarget.getTarget();
if (target == null) return;
switch (target) {
case FIELD:
checkFieldTargetApplicability(modifierListOwner, descriptor, annotation);
break;
case FILE:
throw new IllegalArgumentException("@file annotations are not allowed here");
}
}
}
private void checkFieldTargetApplicability(
JetDeclaration modifierListOwner,
DeclarationDescriptor descriptor,
AnnotationDescriptor annotation
) {
if (reportIfNotPropertyDescriptor(descriptor, annotation, INAPPLICABLE_FIELD_TARGET)) return;
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
boolean hasDelegate = modifierListOwner instanceof JetProperty && ((JetProperty) modifierListOwner).hasDelegate();
if (!hasDelegate && Boolean.FALSE.equals(trace.getBindingContext().get(BACKING_FIELD_REQUIRED, propertyDescriptor))) {
reportAnnotationTargetNotApplicable(annotation, INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD);
}
}
private boolean reportIfNotPropertyDescriptor(
DeclarationDescriptor descriptor,
AnnotationDescriptor annotation,
DiagnosticFactory0<PsiElement> diagnosticFactory
) {
if (!(descriptor instanceof PropertyDescriptor)) {
reportAnnotationTargetNotApplicable(annotation, diagnosticFactory);
return true;
}
return false;
}
private void reportAnnotationTargetNotApplicable(AnnotationDescriptor annotation, DiagnosticFactory0<PsiElement> diagnosticFactory) {
JetAnnotationEntry annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation);
if (annotationEntry == null) return;
trace.report(diagnosticFactory.on(annotationEntry));
}
@NotNull
public Map<JetModifierKeywordToken, PsiElement> getTokensCorrespondingToModifiers(
@NotNull JetModifierList modifierList,
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.types.JetType;
@@ -62,8 +63,8 @@ public class ForceResolveUtil {
public static void forceResolveAllContents(@NotNull Annotations annotations) {
doForceResolveAllContents(annotations);
for (AnnotationDescriptor annotation : annotations) {
doForceResolveAllContents(annotation);
for (AnnotationWithTarget annotationWithTarget : annotations.getAllAnnotations()) {
doForceResolveAllContents(annotationWithTarget.getAnnotation());
}
}
@@ -18,9 +18,13 @@ package org.jetbrains.kotlin.resolve.lazy.descriptors
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.JetAnnotationEntry
import org.jetbrains.kotlin.psi.JetAnnotationUseSiteTarget
import org.jetbrains.kotlin.resolve.AnnotationResolver
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
@@ -33,9 +37,9 @@ import org.jetbrains.kotlin.resolve.source.toSourceElement
import org.jetbrains.kotlin.storage.StorageManager
abstract class LazyAnnotationsContext(
val annotationResolver: AnnotationResolver,
val storageManager: StorageManager,
val trace: BindingTrace
val annotationResolver: AnnotationResolver,
val storageManager: StorageManager,
val trace: BindingTrace
) {
abstract val scope: LexicalScope
}
@@ -55,7 +59,10 @@ public class LazyAnnotations(
private val annotation = c.storageManager.createMemoizedFunction {
entry: JetAnnotationEntry ->
LazyAnnotationDescriptor(c, entry)
val descriptor = LazyAnnotationDescriptor(c, entry)
val target = entry.getUseSiteTarget()?.getAnnotationUseSiteTarget()
AnnotationWithTarget(descriptor, target)
}
override fun findAnnotation(fqName: FqName): AnnotationDescriptor? {
@@ -65,8 +72,7 @@ public class LazyAnnotations(
val annotationType = annotationDescriptor.getType()
if (annotationType.isError()) continue
val descriptor = annotationType.getConstructor().getDeclarationDescriptor()
if (descriptor == null) continue
val descriptor = annotationType.getConstructor().getDeclarationDescriptor() ?: continue
if (DescriptorUtils.getFqNameSafe(descriptor) == fqName) {
return annotationDescriptor
@@ -78,11 +84,29 @@ public class LazyAnnotations(
override fun findExternalAnnotation(fqName: FqName) = null
override fun iterator(): Iterator<AnnotationDescriptor> = annotationEntries.asSequence().map(annotation).iterator()
override fun getUseSiteTargetedAnnotations(): List<AnnotationWithTarget> {
return annotationEntries
.asSequence()
.map {
val (descriptor, target) = annotation(it)
if (target == null) null else AnnotationWithTarget(descriptor, target)
}.filterNotNull().toList()
}
override fun getAllAnnotations() = annotationEntries.map(annotation)
override fun iterator(): Iterator<AnnotationDescriptor> {
return annotationEntries
.asSequence()
.map {
val (descriptor, target) = annotation(it)
if (target == null) descriptor else null // Filter out annotations with target
}.filterNotNull().iterator()
}
override fun forceResolveAllContents() {
// To resolve all entries
this.toList()
getAllAnnotations()
}
}
+2 -1
View File
@@ -2,7 +2,8 @@ JetFile: DocCommentAfterFileAnnotations.kt
FILE_ANNOTATION_LIST
ANNOTATION
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
ANNOTATION_ENTRY
+3 -2
View File
@@ -2,7 +2,8 @@ JetFile: LineCommentAfterFileAnnotations.kt
FILE_ANNOTATION_LIST
ANNOTATION
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
ANNOTATION_ENTRY
@@ -25,4 +26,4 @@ JetFile: LineCommentAfterFileAnnotations.kt
PsiElement(IDENTIFIER)('C')
CLASS_BODY
PsiElement(LBRACE)('{')
PsiElement(RBRACE)('}')
PsiElement(RBRACE)('}')
@@ -11,7 +11,7 @@ JetFile: fileAnnotationInWrongPlace.kt
MODIFIER_LIST
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiErrorElement:File annotations are only allowed before package declaration
PsiErrorElement:@file annotations are only allowed before package declaration
PsiElement(file)('file')
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
@@ -28,7 +28,7 @@ JetFile: fileAnnotationInWrongPlace.kt
MODIFIER_LIST
ANNOTATION
PsiElement(AT)('@')
PsiErrorElement:File annotations are only allowed before package declaration
PsiErrorElement:@file annotations are only allowed before package declaration
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
@@ -62,7 +62,7 @@ JetFile: fileAnnotationInWrongPlace.kt
MODIFIER_LIST
ANNOTATION
PsiElement(AT)('@')
PsiErrorElement:File annotations are only allowed before package declaration
PsiErrorElement:@file annotations are only allowed before package declaration
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
@@ -80,7 +80,7 @@ JetFile: fileAnnotationInWrongPlace.kt
PsiWhiteSpace('\n\n')
CLASS
MODIFIER_LIST
PsiErrorElement:Expected annotation identifier after '@file:'
PsiErrorElement:Expected annotation identifier after ':'
PsiElement(AT)('@')
PsiElement(IDENTIFIER)('file')
PsiElement(COLON)(':')
@@ -93,7 +93,7 @@ JetFile: fileAnnotationInWrongPlace.kt
MODIFIER_LIST
ANNOTATION
PsiElement(AT)('@')
PsiErrorElement:File annotations are only allowed before package declaration
PsiErrorElement:@file annotations are only allowed before package declaration
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
@@ -103,4 +103,4 @@ JetFile: fileAnnotationInWrongPlace.kt
PsiWhiteSpace('\n')
PsiElement(trait)('trait')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('T')
PsiElement(IDENTIFIER)('T')
@@ -2,7 +2,8 @@ JetFile: manyAnnotationBlocks.kt
FILE_ANNOTATION_LIST
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
@@ -12,7 +13,8 @@ JetFile: manyAnnotationBlocks.kt
PsiWhiteSpace('\n')
ANNOTATION
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
ANNOTATION_ENTRY
@@ -2,7 +2,8 @@ JetFile: manyInOneAnnotationBlock.kt
FILE_ANNOTATION_LIST
ANNOTATION
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
PsiElement(LBRACKET)('[')
@@ -12,7 +12,8 @@ JetFile: nonFIleAnnotationBeforePackage.kt
PsiWhiteSpace('\n')
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiWhiteSpace(' ')
PsiErrorElement:Expecting "file:" prefix for file annotations
PsiElement(AT)('@')
@@ -22,14 +23,14 @@ JetFile: nonFIleAnnotationBeforePackage.kt
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('bar')
PsiWhiteSpace('\n')
PsiErrorElement:Expected annotation identifier after '@file:'
PsiErrorElement:Expected annotation identifier after ':'
PsiElement(AT)('@')
PsiElement(IDENTIFIER)('file')
PsiElement(COLON)(':')
PsiWhiteSpace('\n')
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiErrorElement:Expected 'file' keyword before ':'
PsiErrorElement:Expected annotation target before ':'
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
@@ -39,7 +40,7 @@ JetFile: nonFIleAnnotationBeforePackage.kt
PsiWhiteSpace('\n')
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiErrorElement:Expected 'file' keyword before ':'
PsiErrorElement:Expected annotation target before ':'
PsiElement(IDENTIFIER)('fil')
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
+2 -1
View File
@@ -2,7 +2,8 @@ JetFile: single.kt
FILE_ANNOTATION_LIST
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
+4 -3
View File
@@ -2,7 +2,8 @@ JetFile: withoutPackage.kt
FILE_ANNOTATION_LIST
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
@@ -34,7 +35,7 @@ JetFile: withoutPackage.kt
PsiWhiteSpace('\n')
ANNOTATION
PsiElement(AT)('@')
PsiErrorElement:File annotations are only allowed before package declaration
PsiErrorElement:@file annotations are only allowed before package declaration
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
@@ -55,4 +56,4 @@ JetFile: withoutPackage.kt
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiElement(RBRACE)('}')
PsiElement(RBRACE)('}')
@@ -2,7 +2,8 @@ JetFile: withoutPackageWithSimpleAnnotation.kt
FILE_ANNOTATION_LIST
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
@@ -32,7 +33,7 @@ JetFile: withoutPackageWithSimpleAnnotation.kt
PsiWhiteSpace('\n')
ANNOTATION_ENTRY
PsiElement(AT)('@')
PsiErrorElement:File annotations are only allowed before package declaration
PsiErrorElement:@file annotations are only allowed before package declaration
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
@@ -51,4 +52,4 @@ JetFile: withoutPackageWithSimpleAnnotation.kt
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiElement(RBRACE)('}')
PsiElement(RBRACE)('}')
+5 -3
View File
@@ -2,7 +2,8 @@ JetFile: manyAnnotationsOnFile.kts
FILE_ANNOTATION_LIST
ANNOTATION
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
PsiWhiteSpace(' ')
@@ -16,7 +17,8 @@ JetFile: manyAnnotationsOnFile.kts
PsiWhiteSpace('\n')
ANNOTATION
PsiElement(AT)('@')
PsiElement(file)('file')
ANNOTATION_TARGET
PsiElement(file)('file')
PsiElement(COLON)(':')
PsiElement(LBRACKET)('[')
ANNOTATION_ENTRY
@@ -43,4 +45,4 @@ JetFile: manyAnnotationsOnFile.kts
<empty list>
SCRIPT
BLOCK
<empty list>
<empty list>
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.load.java.lazy
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.load.java.components.JavaAnnotationMapper
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
@@ -38,6 +39,10 @@ class LazyJavaAnnotations(
override fun findExternalAnnotation(fqName: FqName) =
c.components.externalAnnotationResolver.findExternalAnnotation(annotationOwner, fqName)?.let(annotationDescriptors)
override fun getUseSiteTargetedAnnotations() = emptyList<AnnotationWithTarget>()
override fun getAllAnnotations() = this.map { AnnotationWithTarget(it, null) }
override fun iterator() =
(annotationOwner.annotations.asSequence().map(annotationDescriptors)
+ JavaAnnotationMapper.findMappedJavaAnnotation(KotlinBuiltIns.FQ_NAMES.annotation, annotationOwner, c)
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.load.java.typeEnhacement
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
@@ -175,6 +176,10 @@ private class EnhancedTypeAnnotations(private val fqNameToMatch: FqName) : Annot
override fun findExternalAnnotation(fqName: FqName) = null
override fun getAllAnnotations() = this.map { AnnotationWithTarget(it, null) }
override fun getUseSiteTargetedAnnotations() = emptyList<AnnotationWithTarget>()
// Note, that this class may break Annotations contract (!isEmpty && iterator.isEmpty())
// It's a hack that we need unless we have stable "user data" in JetType
override fun iterator(): Iterator<AnnotationDescriptor> = emptyList<AnnotationDescriptor>().iterator()
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.descriptors.annotations
public enum class AnnotationUseSiteTarget() {
FIELD,
FILE
}
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.descriptors.annotations
import org.jetbrains.kotlin.name.FqName
public data class AnnotationWithTarget(val annotation: AnnotationDescriptor, val target: AnnotationUseSiteTarget?)
private class UseSiteTargetedAnnotations(
private val original: Annotations,
private val additionalAnnotations: Annotations
) : Annotations {
override fun isEmpty() = original.isEmpty()
override fun findAnnotation(fqName: FqName) = original.findAnnotation(fqName)
override fun findExternalAnnotation(fqName: FqName) = original.findExternalAnnotation(fqName)
private fun getAdditionalTargetedAnnotations() = additionalAnnotations.getUseSiteTargetedAnnotations()
override fun getUseSiteTargetedAnnotations(): List<AnnotationWithTarget> {
return original.getUseSiteTargetedAnnotations() + getAdditionalTargetedAnnotations()
}
override fun getAllAnnotations(): List<AnnotationWithTarget> {
return original.getAllAnnotations() + getAdditionalTargetedAnnotations()
}
override fun iterator() = original.iterator()
}
public class AnnotatedWithAdditionalAnnotations(
delegate: Annotated?,
additional: Annotated
) : Annotated {
private val annotations: Annotations = UseSiteTargetedAnnotations(delegate?.annotations ?: Annotations.EMPTY, additional.annotations)
override fun getAnnotations() = annotations
}
@@ -27,6 +27,20 @@ public interface Annotations : Iterable<AnnotationDescriptor> {
public fun findExternalAnnotation(fqName: FqName): AnnotationDescriptor?
public fun getUseSiteTargetedAnnotations(): List<AnnotationWithTarget>
public fun getUseSiteTargetedAnnotations(target: AnnotationUseSiteTarget): List<AnnotationDescriptor> {
return getUseSiteTargetedAnnotations().fold(arrayListOf<AnnotationDescriptor>()) { list, targeted ->
if (target == targeted.target) {
list.add(targeted.annotation)
}
list
}
}
// Returns both targeted and annotations without target. Annotation order is preserved.
public fun getAllAnnotations(): List<AnnotationWithTarget>
companion object {
public val EMPTY: Annotations = object : Annotations {
override fun isEmpty() = true
@@ -35,6 +49,10 @@ public interface Annotations : Iterable<AnnotationDescriptor> {
override fun findExternalAnnotation(fqName: FqName) = null
override fun getUseSiteTargetedAnnotations() = emptyList<AnnotationWithTarget>()
override fun getAllAnnotations() = emptyList<AnnotationWithTarget>()
override fun iterator() = emptyList<AnnotationDescriptor>().iterator()
override fun toString() = "EMPTY"
@@ -54,14 +72,22 @@ class FilteredAnnotations(
if (fqNameFilter(fqName)) delegate.findExternalAnnotation(fqName)
else null
override fun iterator() = delegate.asSequence()
.filter { annotation ->
val descriptor = annotation.getType().getConstructor().getDeclarationDescriptor()
descriptor != null && DescriptorUtils.getFqName(descriptor).let { fqName ->
fqName.isSafe() && fqNameFilter(fqName.toSafe())
}
}
.iterator()
override fun getUseSiteTargetedAnnotations(): List<AnnotationWithTarget> {
return delegate.getUseSiteTargetedAnnotations().filter { shouldBeReturned(it.annotation) }
}
override fun getAllAnnotations(): List<AnnotationWithTarget> {
return delegate.getAllAnnotations().filter { shouldBeReturned(it.annotation) }
}
override fun iterator() = delegate.filter { shouldBeReturned(it) }.iterator()
private fun shouldBeReturned(annotation: AnnotationDescriptor): Boolean {
val descriptor = annotation.getType().getConstructor().getDeclarationDescriptor()
return descriptor != null && DescriptorUtils.getFqName(descriptor).let { fqName ->
fqName.isSafe() && fqNameFilter(fqName.toSafe())
}
}
override fun isEmpty() = !iterator().hasNext()
}
@@ -77,5 +103,9 @@ class CompositeAnnotations(
override fun findExternalAnnotation(fqName: FqName) = delegates.asSequence().map { it.findExternalAnnotation(fqName) }.filterNotNull().firstOrNull()
override fun getUseSiteTargetedAnnotations() = delegates.flatMap { it.getUseSiteTargetedAnnotations() }
override fun getAllAnnotations() = delegates.flatMap { it.getAllAnnotations() }
override fun iterator() = delegates.asSequence().flatMap { it.asSequence() }.iterator()
}
@@ -19,8 +19,26 @@ package org.jetbrains.kotlin.descriptors.annotations
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import kotlin.platform.platformStatic
public class AnnotationsImpl : Annotations {
private val annotations: List<AnnotationDescriptor>
private val targetedAnnotations: List<AnnotationWithTarget>
constructor(annotations: List<AnnotationDescriptor>) {
this.annotations = annotations
this.targetedAnnotations = annotations.map { AnnotationWithTarget(it, null) }
}
// List<AnnotationDescriptor> and List<AnnotationWithTarget> have the same signature
private constructor(
targetedAnnotations: List<AnnotationWithTarget>,
@suppress("UNUSED_PARAMETER") i: Int
) {
this.targetedAnnotations = targetedAnnotations
this.annotations = targetedAnnotations.filter { it.target == null }.map { it.annotation }
}
public class AnnotationsImpl(private val annotations: List<AnnotationDescriptor>) : Annotations {
override fun isEmpty() = annotations.isEmpty()
override fun findAnnotation(fqName: FqName) = annotations.firstOrNull {
@@ -28,9 +46,24 @@ public class AnnotationsImpl(private val annotations: List<AnnotationDescriptor>
descriptor is ClassDescriptor && fqName.toUnsafe() == DescriptorUtils.getFqName(descriptor)
}
override fun getUseSiteTargetedAnnotations(): List<AnnotationWithTarget> {
return targetedAnnotations
.filter { it.target != null }
.map { AnnotationWithTarget(it.annotation, it.target!!) }
}
override fun getAllAnnotations() = targetedAnnotations
override fun findExternalAnnotation(fqName: FqName) = null
override fun iterator() = annotations.iterator()
override fun toString() = annotations.toString()
companion object {
platformStatic
public fun create(annotationsWithTargets: List<AnnotationWithTarget>): AnnotationsImpl {
return AnnotationsImpl(annotationsWithTargets, 0)
}
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.serialization.deserialization.descriptors
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -40,5 +41,9 @@ class DeserializedAnnotations(
override fun findExternalAnnotation(fqName: FqName) = null
override fun getUseSiteTargetedAnnotations() = emptyList<AnnotationWithTarget>()
override fun getAllAnnotations() = this.map { AnnotationWithTarget(it, null) }
override fun iterator(): Iterator<AnnotationDescriptor> = annotations().iterator()
}
+1 -1
View File
@@ -15,7 +15,7 @@ annotationList
;
annotationPrefix:
: ("@" (":" "file")?)
: ("@" (":" ("file" | "field"))?)
;
unescapedAnnotation