Support @field: annotations
This commit is contained in:
@@ -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 =
|
||||
|
||||
+3
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+32
-8
@@ -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,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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)('}')
|
||||
+4
-3
@@ -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
@@ -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>
|
||||
+5
@@ -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)
|
||||
|
||||
+5
@@ -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()
|
||||
|
||||
+22
@@ -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
|
||||
}
|
||||
+53
@@ -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()
|
||||
}
|
||||
+34
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -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()
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ annotationList
|
||||
;
|
||||
|
||||
annotationPrefix:
|
||||
: ("@" (":" "file")?)
|
||||
: ("@" (":" ("file" | "field"))?)
|
||||
;
|
||||
|
||||
unescapedAnnotation
|
||||
|
||||
Reference in New Issue
Block a user