Refactor ModifiersChecker to be more component-like

A couple of minor prettifications
This commit is contained in:
Pavel V. Talanov
2015-07-22 14:54:35 +03:00
parent ee49d13d89
commit f5878eddd4
12 changed files with 377 additions and 336 deletions
@@ -54,6 +54,7 @@ import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
public class BodyResolver {
@NotNull private final ScriptBodyResolver scriptBodyResolverResolver;
@NotNull private final ModifiersChecker modifiersChecker;
@NotNull private final ExpressionTypingServices expressionTypingServices;
@NotNull private final CallResolver callResolver;
@NotNull private final ObservableBindingTrace trace;
@@ -78,7 +79,8 @@ public class BodyResolver {
@NotNull FunctionAnalyzerExtension functionAnalyzerExtension,
@NotNull ScriptBodyResolver scriptBodyResolverResolver,
@NotNull BindingTrace trace,
@NotNull ValueParameterResolver valueParameterResolver
@NotNull ValueParameterResolver valueParameterResolver,
@NotNull ModifiersChecker modifiersChecker
) {
this.additionalCheckerProvider = additionalCheckerProvider;
this.annotationResolver = annotationResolver;
@@ -90,6 +92,7 @@ public class BodyResolver {
this.expressionTypingServices = expressionTypingServices;
this.functionAnalyzerExtension = functionAnalyzerExtension;
this.scriptBodyResolverResolver = scriptBodyResolverResolver;
this.modifiersChecker = modifiersChecker;
this.trace = new ObservableBindingTrace(trace);
this.valueParameterResolver = valueParameterResolver;
}
@@ -512,7 +515,7 @@ public class BodyResolver {
annotationResolver.resolveAnnotationsWithArguments(scope, modifierList, trace);
ModifiersChecker.reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY), trace);
modifiersChecker.withTrace(trace).reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY));
}
private void resolvePrimaryConstructorParameters(@NotNull BodiesResolveContext c) {
@@ -45,7 +45,7 @@ import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembe
public class DeclarationsChecker {
@NotNull private final BindingTrace trace;
@NotNull private final ModifiersChecker modifiersChecker;
@NotNull private final ModifiersChecker.ModifiersCheckingProcedure modifiersChecker;
@NotNull private final DescriptorResolver descriptorResolver;
public DeclarationsChecker(
@@ -54,7 +54,7 @@ public class DeclarationsChecker {
@NotNull BindingTrace trace
) {
this.descriptorResolver = descriptorResolver;
this.modifiersChecker = modifiersChecker;
this.modifiersChecker = modifiersChecker.withTrace(trace);
this.trace = trace;
}
@@ -143,7 +143,7 @@ public class DeclarationsChecker {
}
AnnotationTargetChecker.INSTANCE$.check(packageDirective, trace, null);
ModifiersChecker.reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY), trace);
modifiersChecker.reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY));
}
private void checkTypesInClassHeader(@NotNull JetClassOrObject classOrObject) {
@@ -532,7 +532,7 @@ public class DeclarationsChecker {
PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null;
if (getterModifierList != null && getterDescriptor != null) {
Map<JetModifierKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets
Map<JetModifierKeywordToken, ASTNode> nodes = modifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets
.newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD,
JetTokens.INTERNAL_KEYWORD));
if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) {
@@ -61,12 +61,6 @@ import static org.jetbrains.kotlin.resolve.source.SourcePackage.toSourceElement;
public class DescriptorResolver {
public static final Name COPY_METHOD_NAME = Name.identifier("copy");
private static final Set<JetModifierKeywordToken> MODIFIERS_ILLEGAL_ON_PARAMETERS;
static {
MODIFIERS_ILLEGAL_ON_PARAMETERS = Sets.newHashSet();
MODIFIERS_ILLEGAL_ON_PARAMETERS.addAll(Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY));
MODIFIERS_ILLEGAL_ON_PARAMETERS.remove(JetTokens.VARARG_KEYWORD);
}
@NotNull private final TypeResolver typeResolver;
@NotNull private final AnnotationResolver annotationResolver;
@@ -1165,24 +1159,6 @@ public class DescriptorResolver {
return getParentOfType(scope.getContainingDeclaration(), ClassDescriptor.class, false);
}
public static void checkParameterHasNoValOrVar(
@NotNull BindingTrace trace,
@NotNull JetParameter parameter,
@NotNull DiagnosticFactory1<PsiElement, JetKeywordToken> diagnosticFactory
) {
PsiElement valOrVar = parameter.getValOrVarKeyword();
if (valOrVar != null) {
trace.report(diagnosticFactory.on(valOrVar, ((JetKeywordToken) valOrVar.getNode().getElementType())));
}
}
public static void checkParameterHasNoModifier(
@NotNull BindingTrace trace,
@NotNull JetParameter parameter
) {
ModifiersChecker.reportIllegalModifiers(parameter.getModifierList(), MODIFIERS_ILLEGAL_ON_PARAMETERS, trace);
}
public static void resolvePackageHeader(
@NotNull JetPackageDirective packageDirective,
@NotNull ModuleDescriptor module,
@@ -16,13 +16,14 @@
package org.jetbrains.kotlin.resolve
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.descriptors.impl.ConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.FunctionExpressionDescriptor
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl.create
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.name.Name
@@ -33,6 +34,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils.*
import org.jetbrains.kotlin.resolve.DescriptorResolver.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.scopes.WritableScope
import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl
import org.jetbrains.kotlin.resolve.source.toSourceElement
@@ -47,12 +49,13 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import java.util.ArrayList
class FunctionDescriptorResolver(
val typeResolver: TypeResolver,
val descriptorResolver: DescriptorResolver,
val annotationResolver: AnnotationResolver,
val storageManager: StorageManager,
val expressionTypingServices: ExpressionTypingServices,
val builtIns: KotlinBuiltIns
private val typeResolver: TypeResolver,
private val descriptorResolver: DescriptorResolver,
private val annotationResolver: AnnotationResolver,
private val storageManager: StorageManager,
private val expressionTypingServices: ExpressionTypingServices,
private val builtIns: KotlinBuiltIns,
private val modifiersChecker: ModifiersChecker
) {
public fun resolveFunctionDescriptor(
containingDescriptor: DeclarationDescriptor,
@@ -336,11 +339,13 @@ class FunctionDescriptorResolver(
if (functionDescriptor !is ConstructorDescriptor || !functionDescriptor.isPrimary()) {
val isConstructor = functionDescriptor is ConstructorDescriptor
DescriptorResolver.checkParameterHasNoValOrVar(
trace, valueParameter,
if (isConstructor) VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER else VAL_OR_VAR_ON_FUN_PARAMETER
)
DescriptorResolver.checkParameterHasNoModifier(trace, valueParameter)
with (modifiersChecker.withTrace(trace)) {
checkParameterHasNoValOrVar(
valueParameter,
if (isConstructor) VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER else VAL_OR_VAR_ON_FUN_PARAMETER
)
checkParameterHasNoModifier(valueParameter)
}
}
else {
checkConstructorParameterHasNoModifier(trace, valueParameter)
@@ -357,7 +362,7 @@ class FunctionDescriptorResolver(
private fun checkConstructorParameterHasNoModifier(trace: BindingTrace, parameter: JetParameter) {
// If is not a property, then it must have no modifier
if (!parameter.hasValOrVar()) {
DescriptorResolver.checkParameterHasNoModifier(trace, parameter)
modifiersChecker.withTrace(trace).checkParameterHasNoModifier(parameter)
}
}
}
@@ -26,7 +26,9 @@ 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.diagnostics.DiagnosticFactory1;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.JetKeywordToken;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.FqName;
@@ -50,188 +52,12 @@ public class ModifiersChecker {
private static final Collection<JetModifierKeywordToken> VISIBILITY_MODIFIERS =
Lists.newArrayList(PRIVATE_KEYWORD, PROTECTED_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD);
public static void reportIllegalModifiers(
@Nullable JetModifierList modifierList,
@NotNull Collection<JetModifierKeywordToken> illegalModifiers,
@NotNull BindingTrace trace
) {
if (modifierList == null) return;
private static final Set<JetModifierKeywordToken> MODIFIERS_ILLEGAL_ON_PARAMETERS;
for (JetModifierKeywordToken modifierToken : illegalModifiers) {
if (modifierList.hasModifier(modifierToken)) {
PsiElement modifierPsi = modifierList.getModifier(modifierToken);
assert modifierPsi != null;
trace.report(ILLEGAL_MODIFIER.on(modifierPsi, modifierToken));
}
}
}
public static void checkIncompatibleModifiers(
@Nullable JetModifierList modifierList,
@NotNull BindingTrace trace,
@NotNull Collection<JetModifierKeywordToken> availableModifiers,
@NotNull Collection<JetModifierKeywordToken>... availableCombinations
) {
if (modifierList == null) return;
Collection<JetModifierKeywordToken> presentModifiers = Sets.newLinkedHashSet();
for (JetModifierKeywordToken modifier : availableModifiers) {
if (modifierList.hasModifier(modifier)) {
presentModifiers.add(modifier);
}
}
checkRepeatedModifiers(modifierList, trace, availableModifiers);
if (presentModifiers.size() == 1) {
return;
}
for (Collection<JetModifierKeywordToken> combination : availableCombinations) {
if (presentModifiers.containsAll(combination) && combination.containsAll(presentModifiers)) {
return;
}
}
for (JetModifierKeywordToken token : presentModifiers) {
trace.report(Errors.INCOMPATIBLE_MODIFIERS.on(modifierList.getModifierNode(token).getPsi(), presentModifiers));
}
}
private static void checkRepeatedModifiers(
@NotNull JetModifierList modifierList,
@NotNull BindingTrace trace,
@NotNull Collection<JetModifierKeywordToken> availableModifiers
) {
for (JetModifierKeywordToken token : availableModifiers) {
if (!modifierList.hasModifier(token)) continue;
List<ASTNode> nodesOfRepeatedTokens = Lists.newArrayList();
ASTNode node = modifierList.getNode().getFirstChildNode();
while (node != null) {
if (node.getElementType() == token) {
nodesOfRepeatedTokens.add(node);
}
node = node.getTreeNext();
}
if (nodesOfRepeatedTokens.size() > 1) {
for (ASTNode repeatedToken : nodesOfRepeatedTokens) {
trace.report(REPEATED_MODIFIER.on(repeatedToken.getPsi(), token));
}
}
}
}
public static void checkIncompatibleVarianceModifiers(@Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
checkIncompatibleModifiers(modifierList, trace, Arrays.asList(JetTokens.IN_KEYWORD, JetTokens.OUT_KEYWORD));
}
@NotNull
private final BindingTrace trace;
@NotNull
private final AdditionalCheckerProvider additionalCheckerProvider;
public ModifiersChecker(@NotNull BindingTrace trace, @NotNull AdditionalCheckerProvider additionalCheckerProvider) {
this.trace = trace;
this.additionalCheckerProvider = additionalCheckerProvider;
}
public static ModifiersChecker create(@NotNull BindingTrace trace, @NotNull AdditionalCheckerProvider provider) {
return new ModifiersChecker(trace, provider);
}
public void checkModifiersForDeclaration(@NotNull JetDeclaration modifierListOwner, @NotNull MemberDescriptor descriptor) {
if (modifierListOwner instanceof JetEnumEntry) {
reportIllegalModifiers(modifierListOwner, Arrays.asList(MODIFIER_KEYWORDS_ARRAY));
}
else {
checkInnerModifier(modifierListOwner, descriptor);
checkDefaultModifier(modifierListOwner);
checkModalityModifiers(modifierListOwner);
checkVisibilityModifiers(modifierListOwner, descriptor);
checkVarianceModifiers(modifierListOwner);
checkVarargsModifiers(modifierListOwner, descriptor);
}
checkPlatformNameApplicability(descriptor);
runDeclarationCheckers(modifierListOwner, descriptor);
AnnotationTargetChecker.INSTANCE$.check(modifierListOwner, trace,
descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null);
}
private void checkVarargsModifiers(@NotNull JetDeclaration owner, @NotNull MemberDescriptor descriptor) {
if (!(owner instanceof JetParameter)) {
reportIllegalModifiers(owner, Collections.singleton(VARARG_KEYWORD));
}
}
public void checkModifiersForLocalDeclaration(@NotNull JetDeclaration modifierListOwner, @NotNull DeclarationDescriptor descriptor) {
reportIllegalModalityModifiers(modifierListOwner);
reportIllegalVisibilityModifiers(modifierListOwner);
checkPlatformNameApplicability(descriptor);
runDeclarationCheckers(modifierListOwner, descriptor);
AnnotationTargetChecker.INSTANCE$.check(modifierListOwner, trace,
descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null);
}
public void reportIllegalModalityModifiers(@NotNull JetModifierListOwner modifierListOwner) {
reportIllegalModifiers(modifierListOwner, MODALITY_MODIFIERS);
}
public void reportIllegalVisibilityModifiers(@NotNull JetModifierListOwner modifierListOwner) {
reportIllegalModifiers(modifierListOwner, VISIBILITY_MODIFIERS);
}
private void checkModalityModifiers(@NotNull JetModifierListOwner modifierListOwner) {
JetModifierList modifierList = modifierListOwner.getModifierList();
if (modifierList == null) return;
checkRedundantModifier(modifierList, Pair.create(OPEN_KEYWORD, ABSTRACT_KEYWORD), Pair.create(OPEN_KEYWORD, OVERRIDE_KEYWORD));
checkCompatibility(modifierList, Arrays.asList(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD),
Arrays.asList(ABSTRACT_KEYWORD, OPEN_KEYWORD));
if (modifierListOwner instanceof JetObjectDeclaration) {
reportIllegalModalityModifiers(modifierListOwner);
}
else if (modifierListOwner instanceof JetClassOrObject) {
reportIllegalModifiers(modifierListOwner, Collections.singletonList(OVERRIDE_KEYWORD));
}
}
private void checkVisibilityModifiers(@NotNull JetModifierListOwner modifierListOwner, @NotNull DeclarationDescriptor descriptor) {
JetModifierList modifierList = modifierListOwner.getModifierList();
if (modifierList == null) return;
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof PackageFragmentDescriptor) {
if (modifierList.hasModifier(PROTECTED_KEYWORD)) {
trace.report(Errors.PACKAGE_MEMBER_CANNOT_BE_PROTECTED.on(modifierListOwner));
}
}
checkCompatibility(modifierList, VISIBILITY_MODIFIERS);
}
private void checkInnerModifier(@NotNull JetModifierListOwner modifierListOwner, @NotNull DeclarationDescriptor descriptor) {
if (modifierListOwner.hasModifier(INNER_KEYWORD)) {
switch (checkIllegalInner(descriptor)) {
case ALLOWED:
break;
case ILLEGAL_POSITION:
reportIllegalModifiers(modifierListOwner, Collections.singletonList(INNER_KEYWORD));
break;
case IN_TRAIT:
trace.report(INNER_CLASS_IN_TRAIT.on(modifierListOwner));
break;
case IN_OBJECT:
trace.report(INNER_CLASS_IN_OBJECT.on(modifierListOwner));
break;
}
return;
}
if (modifierListOwner instanceof JetClass && !(modifierListOwner instanceof JetEnumEntry)) {
JetClass aClass = (JetClass) modifierListOwner;
boolean localEnumError = aClass.isLocal() && aClass.isEnum();
if (!localEnumError && isIllegalNestedClass(descriptor)) {
trace.report(NESTED_CLASS_NOT_ALLOWED.on(aClass));
}
}
static {
MODIFIERS_ILLEGAL_ON_PARAMETERS = Sets.newHashSet();
MODIFIERS_ILLEGAL_ON_PARAMETERS.addAll(Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY));
MODIFIERS_ILLEGAL_ON_PARAMETERS.remove(JetTokens.VARARG_KEYWORD);
}
public static boolean isIllegalInner(@NotNull DeclarationDescriptor descriptor) {
@@ -245,15 +71,10 @@ public class ModifiersChecker {
IN_OBJECT,
}
private void checkDefaultModifier(@NotNull JetDeclaration declaration) {
if (declaration.hasModifier(COMPANION_KEYWORD) && !isDefaultModifierAllowed(declaration)) {
reportIllegalModifiers(declaration, Collections.singletonList(COMPANION_KEYWORD));
}
}
// NOTE: just checks if this is legal context for companion modifier (Companion object descriptor can be created)
// COMPANION_OBJECT_NOT_ALLOWED can be reported later
public static boolean isDefaultModifierAllowed(@NotNull JetDeclaration declaration) {
public static boolean isCompanionModifierAllowed(@NotNull JetDeclaration declaration) {
if (declaration instanceof JetObjectDeclaration) {
JetDeclaration containingDeclaration = getContainingDeclaration(declaration);
if (containingDeclaration instanceof JetClassOrObject) {
@@ -264,7 +85,7 @@ public class ModifiersChecker {
}
@NotNull
private static InnerModifierCheckResult checkIllegalInner(DeclarationDescriptor descriptor) {
private static InnerModifierCheckResult checkIllegalInner(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof ClassDescriptor)) return InnerModifierCheckResult.ILLEGAL_POSITION;
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
@@ -292,81 +113,15 @@ public class ModifiersChecker {
return containingClass.isInner() || containingClass.getContainingDeclaration() instanceof FunctionDescriptor;
}
private void checkPlatformNameApplicability(@NotNull DeclarationDescriptor descriptor) {
AnnotationDescriptor annotation = descriptor.getAnnotations().findAnnotation(new FqName("kotlin.platform.platformName"));
if (annotation == null) return;
JetAnnotationEntry annotationEntry = trace.get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation);
if (annotationEntry == null) return;
if (descriptor instanceof FunctionDescriptor && !isRenamableFunction((FunctionDescriptor) descriptor)) {
trace.report(INAPPLICABLE_PLATFORM_NAME.on(annotationEntry));
}
String value = null;
Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values();
if (!values.isEmpty()) {
ConstantValue<?> name = values.iterator().next();
if (name instanceof StringValue) {
value = ((StringValue) name).getValue();
}
}
if (value == null || !Name.isValidIdentifier(value)) {
trace.report(ILLEGAL_PLATFORM_NAME.on(annotationEntry, String.valueOf(value)));
}
if (descriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) descriptor;
if (DescriptorUtils.isOverride(callableMemberDescriptor) || callableMemberDescriptor.getModality().isOverridable()) {
trace.report(INAPPLICABLE_PLATFORM_NAME.on(annotationEntry));
}
}
}
private static boolean isRenamableFunction(@NotNull FunctionDescriptor descriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
return containingDescriptor instanceof PackageFragmentDescriptor || containingDescriptor instanceof ClassDescriptor;
}
private void checkCompatibility(@Nullable JetModifierList modifierList, Collection<JetModifierKeywordToken> availableModifiers, Collection<JetModifierKeywordToken>... availableCombinations) {
checkIncompatibleModifiers(modifierList, trace, availableModifiers, availableCombinations);
}
private void checkRedundantModifier(@NotNull JetModifierList modifierList, Pair<JetModifierKeywordToken, JetModifierKeywordToken>... redundantBundles) {
for (Pair<JetModifierKeywordToken, JetModifierKeywordToken> tokenPair : redundantBundles) {
JetModifierKeywordToken redundantModifier = tokenPair.getFirst();
JetModifierKeywordToken sufficientModifier = tokenPair.getSecond();
if (modifierList.hasModifier(redundantModifier) && modifierList.hasModifier(sufficientModifier)) {
trace.report(Errors.REDUNDANT_MODIFIER.on(modifierList.getModifierNode(redundantModifier).getPsi(), redundantModifier, sufficientModifier));
}
}
}
public void reportIllegalModifiers(
@NotNull
public static Modality resolveModalityFromModifiers(
@NotNull JetModifierListOwner modifierListOwner,
@NotNull Collection<JetModifierKeywordToken> illegalModifiers
@NotNull Modality defaultModality
) {
reportIllegalModifiers(modifierListOwner.getModifierList(), illegalModifiers, trace);
}
@NotNull
public static Map<JetModifierKeywordToken, ASTNode> getNodesCorrespondingToModifiers(@NotNull JetModifierList modifierList, @NotNull Collection<JetModifierKeywordToken> possibleModifiers) {
Map<JetModifierKeywordToken, ASTNode> nodes = Maps.newHashMap();
for (JetModifierKeywordToken modifier : possibleModifiers) {
if (modifierList.hasModifier(modifier)) {
nodes.put(modifier, modifierList.getModifierNode(modifier));
}
}
return nodes;
}
@NotNull
public static Modality resolveModalityFromModifiers(@NotNull JetModifierListOwner modifierListOwner, @NotNull Modality defaultModality) {
return resolveModalityFromModifiers(modifierListOwner.getModifierList(), defaultModality);
}
@NotNull
public static Modality resolveModalityFromModifiers(@Nullable JetModifierList modifierList, @NotNull Modality defaultModality) {
if (modifierList == null) return defaultModality;
boolean hasAbstractModifier = modifierList.hasModifier(ABSTRACT_KEYWORD);
@@ -395,7 +150,10 @@ public class ModifiersChecker {
}
@NotNull
public static Visibility resolveVisibilityFromModifiers(@NotNull JetModifierListOwner modifierListOwner, @NotNull Visibility defaultVisibility) {
public static Visibility resolveVisibilityFromModifiers(
@NotNull JetModifierListOwner modifierListOwner,
@NotNull Visibility defaultVisibility
) {
return resolveVisibilityFromModifiers(modifierListOwner.getModifierList(), defaultVisibility);
}
@@ -421,19 +179,317 @@ public class ModifiersChecker {
return Visibilities.INTERNAL;
}
private void runDeclarationCheckers(@NotNull JetDeclaration declaration, @NotNull DeclarationDescriptor descriptor) {
for (DeclarationChecker checker : additionalCheckerProvider.getDeclarationCheckers()) {
checker.check(declaration, descriptor, trace, trace.getBindingContext());
public class ModifiersCheckingProcedure {
@NotNull
private final BindingTrace trace;
private ModifiersCheckingProcedure(@NotNull BindingTrace trace) {
this.trace = trace;
}
public void checkParameterHasNoValOrVar(
@NotNull JetParameter parameter,
@NotNull DiagnosticFactory1<PsiElement, JetKeywordToken> diagnosticFactory
) {
PsiElement valOrVar = parameter.getValOrVarKeyword();
if (valOrVar != null) {
trace.report(diagnosticFactory.on(valOrVar, ((JetKeywordToken) valOrVar.getNode().getElementType())));
}
}
public void reportIllegalModifiers(
@Nullable JetModifierList modifierList,
@NotNull Collection<JetModifierKeywordToken> illegalModifiers
) {
if (modifierList == null) return;
for (JetModifierKeywordToken modifierToken : illegalModifiers) {
if (modifierList.hasModifier(modifierToken)) {
PsiElement modifierPsi = modifierList.getModifier(modifierToken);
assert modifierPsi != null;
trace.report(ILLEGAL_MODIFIER.on(modifierPsi, modifierToken));
}
}
}
public void reportIllegalModifiers(
@NotNull JetModifierListOwner modifierListOwner,
@NotNull Collection<JetModifierKeywordToken> illegalModifiers
) {
reportIllegalModifiers(modifierListOwner.getModifierList(), illegalModifiers);
}
public void checkIncompatibleModifiers(
@Nullable JetModifierList modifierList,
@NotNull Collection<JetModifierKeywordToken> availableModifiers,
@NotNull Collection<JetModifierKeywordToken>... availableCombinations
) {
if (modifierList == null) return;
Collection<JetModifierKeywordToken> presentModifiers = Sets.newLinkedHashSet();
for (JetModifierKeywordToken modifier : availableModifiers) {
if (modifierList.hasModifier(modifier)) {
presentModifiers.add(modifier);
}
}
checkRepeatedModifiers(modifierList, availableModifiers);
if (presentModifiers.size() == 1) {
return;
}
for (Collection<JetModifierKeywordToken> combination : availableCombinations) {
if (presentModifiers.containsAll(combination) && combination.containsAll(presentModifiers)) {
return;
}
}
for (JetModifierKeywordToken token : presentModifiers) {
trace.report(Errors.INCOMPATIBLE_MODIFIERS.on(modifierList.getModifierNode(token).getPsi(), presentModifiers));
}
}
private void checkRepeatedModifiers(
@NotNull JetModifierList modifierList,
@NotNull Collection<JetModifierKeywordToken> availableModifiers
) {
for (JetModifierKeywordToken token : availableModifiers) {
if (!modifierList.hasModifier(token)) continue;
List<ASTNode> nodesOfRepeatedTokens = Lists.newArrayList();
ASTNode node = modifierList.getNode().getFirstChildNode();
while (node != null) {
if (node.getElementType() == token) {
nodesOfRepeatedTokens.add(node);
}
node = node.getTreeNext();
}
if (nodesOfRepeatedTokens.size() > 1) {
for (ASTNode repeatedToken : nodesOfRepeatedTokens) {
trace.report(REPEATED_MODIFIER.on(repeatedToken.getPsi(), token));
}
}
}
}
public void checkIncompatibleVarianceModifiers(@Nullable JetModifierList modifierList) {
checkIncompatibleModifiers(modifierList, Arrays.asList(JetTokens.IN_KEYWORD, JetTokens.OUT_KEYWORD));
}
public void checkModifiersForDeclaration(@NotNull JetDeclaration modifierListOwner, @NotNull MemberDescriptor descriptor) {
if (modifierListOwner instanceof JetEnumEntry) {
reportIllegalModifiers(modifierListOwner.getModifierList(), Arrays.asList(MODIFIER_KEYWORDS_ARRAY));
}
else {
checkInnerModifier(modifierListOwner, descriptor);
checkCompanionModifier(modifierListOwner);
checkModalityModifiers(modifierListOwner);
checkVisibilityModifiers(modifierListOwner, descriptor);
checkVarianceModifiers(modifierListOwner);
checkVarargsModifiers(modifierListOwner, descriptor);
}
checkPlatformNameApplicability(descriptor);
runDeclarationCheckers(modifierListOwner, descriptor);
AnnotationTargetChecker.INSTANCE$.check(modifierListOwner, trace,
descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null);
}
private void checkVarargsModifiers(@NotNull JetDeclaration owner, @NotNull MemberDescriptor descriptor) {
if (!(owner instanceof JetParameter)) {
reportIllegalModifiers(owner.getModifierList(), Collections.singleton(VARARG_KEYWORD));
}
}
public void checkModifiersForLocalDeclaration(
@NotNull JetDeclaration modifierListOwner,
@NotNull DeclarationDescriptor descriptor
) {
reportIllegalModalityModifiers(modifierListOwner);
reportIllegalVisibilityModifiers(modifierListOwner);
checkPlatformNameApplicability(descriptor);
runDeclarationCheckers(modifierListOwner, descriptor);
AnnotationTargetChecker.INSTANCE$.check(modifierListOwner, trace,
descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null);
}
public void reportIllegalModalityModifiers(@NotNull JetModifierListOwner modifierListOwner) {
reportIllegalModifiers(modifierListOwner, MODALITY_MODIFIERS);
}
public void reportIllegalVisibilityModifiers(@NotNull JetModifierListOwner modifierListOwner) {
reportIllegalModifiers(modifierListOwner, VISIBILITY_MODIFIERS);
}
private void checkModalityModifiers(@NotNull JetModifierListOwner modifierListOwner) {
JetModifierList modifierList = modifierListOwner.getModifierList();
if (modifierList == null) return;
checkRedundantModifier(modifierList, Pair.create(OPEN_KEYWORD, ABSTRACT_KEYWORD), Pair.create(OPEN_KEYWORD, OVERRIDE_KEYWORD));
checkCompatibility(modifierList, Arrays.asList(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD),
Arrays.asList(ABSTRACT_KEYWORD, OPEN_KEYWORD));
if (modifierListOwner instanceof JetObjectDeclaration) {
reportIllegalModalityModifiers(modifierListOwner);
}
else if (modifierListOwner instanceof JetClassOrObject) {
reportIllegalModifiers(modifierListOwner, Collections.singletonList(OVERRIDE_KEYWORD));
}
}
private void checkVisibilityModifiers(@NotNull JetModifierListOwner modifierListOwner, @NotNull DeclarationDescriptor descriptor) {
JetModifierList modifierList = modifierListOwner.getModifierList();
if (modifierList == null) return;
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof PackageFragmentDescriptor) {
if (modifierList.hasModifier(PROTECTED_KEYWORD)) {
trace.report(Errors.PACKAGE_MEMBER_CANNOT_BE_PROTECTED.on(modifierListOwner));
}
}
checkCompatibility(modifierList, VISIBILITY_MODIFIERS);
}
private void checkInnerModifier(@NotNull JetModifierListOwner modifierListOwner, @NotNull DeclarationDescriptor descriptor) {
if (modifierListOwner.hasModifier(INNER_KEYWORD)) {
switch (checkIllegalInner(descriptor)) {
case ALLOWED:
break;
case ILLEGAL_POSITION:
reportIllegalModifiers(modifierListOwner, Collections.singletonList(INNER_KEYWORD));
break;
case IN_TRAIT:
trace.report(INNER_CLASS_IN_TRAIT.on(modifierListOwner));
break;
case IN_OBJECT:
trace.report(INNER_CLASS_IN_OBJECT.on(modifierListOwner));
break;
}
return;
}
if (modifierListOwner instanceof JetClass && !(modifierListOwner instanceof JetEnumEntry)) {
JetClass aClass = (JetClass) modifierListOwner;
boolean localEnumError = aClass.isLocal() && aClass.isEnum();
if (!localEnumError && isIllegalNestedClass(descriptor)) {
trace.report(NESTED_CLASS_NOT_ALLOWED.on(aClass));
}
}
}
private void checkCompanionModifier(@NotNull JetDeclaration declaration) {
if (declaration.hasModifier(COMPANION_KEYWORD) && !isCompanionModifierAllowed(declaration)) {
reportIllegalModifiers(declaration, Collections.singletonList(COMPANION_KEYWORD));
}
}
private void checkPlatformNameApplicability(@NotNull DeclarationDescriptor descriptor) {
AnnotationDescriptor annotation = descriptor.getAnnotations().findAnnotation(new FqName("kotlin.platform.platformName"));
if (annotation == null) return;
JetAnnotationEntry annotationEntry = trace.get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation);
if (annotationEntry == null) return;
if (descriptor instanceof FunctionDescriptor && !isRenamableFunction((FunctionDescriptor) descriptor)) {
trace.report(INAPPLICABLE_PLATFORM_NAME.on(annotationEntry));
}
String value = null;
Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values();
if (!values.isEmpty()) {
ConstantValue<?> name = values.iterator().next();
if (name instanceof StringValue) {
value = ((StringValue) name).getValue();
}
}
if (value == null || !Name.isValidIdentifier(value)) {
trace.report(ILLEGAL_PLATFORM_NAME.on(annotationEntry, String.valueOf(value)));
}
if (descriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) descriptor;
if (DescriptorUtils.isOverride(callableMemberDescriptor) || callableMemberDescriptor.getModality().isOverridable()) {
trace.report(INAPPLICABLE_PLATFORM_NAME.on(annotationEntry));
}
}
}
private boolean isRenamableFunction(@NotNull FunctionDescriptor descriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
return containingDescriptor instanceof PackageFragmentDescriptor || containingDescriptor instanceof ClassDescriptor;
}
private void checkCompatibility(
@Nullable JetModifierList modifierList,
Collection<JetModifierKeywordToken> availableModifiers,
Collection<JetModifierKeywordToken>... availableCombinations
) {
checkIncompatibleModifiers(modifierList, availableModifiers, availableCombinations);
}
private void checkRedundantModifier(
@NotNull JetModifierList modifierList,
Pair<JetModifierKeywordToken, JetModifierKeywordToken>... redundantBundles
) {
for (Pair<JetModifierKeywordToken, JetModifierKeywordToken> tokenPair : redundantBundles) {
JetModifierKeywordToken redundantModifier = tokenPair.getFirst();
JetModifierKeywordToken sufficientModifier = tokenPair.getSecond();
if (modifierList.hasModifier(redundantModifier) && modifierList.hasModifier(sufficientModifier)) {
trace.report(Errors.REDUNDANT_MODIFIER.on(modifierList.getModifierNode(redundantModifier).getPsi(), redundantModifier,
sufficientModifier));
}
}
}
@NotNull
public Map<JetModifierKeywordToken, ASTNode> getNodesCorrespondingToModifiers(
@NotNull JetModifierList modifierList,
@NotNull Collection<JetModifierKeywordToken> possibleModifiers
) {
Map<JetModifierKeywordToken, ASTNode> nodes = Maps.newHashMap();
for (JetModifierKeywordToken modifier : possibleModifiers) {
if (modifierList.hasModifier(modifier)) {
nodes.put(modifier, modifierList.getModifierNode(modifier));
}
}
return nodes;
}
private void runDeclarationCheckers(@NotNull JetDeclaration declaration, @NotNull DeclarationDescriptor descriptor) {
for (DeclarationChecker checker : additionalCheckerProvider.getDeclarationCheckers()) {
checker.check(declaration, descriptor, trace, trace.getBindingContext());
}
}
public void checkVarianceModifiers(@NotNull JetModifierListOwner modifierListOwner) {
reportIllegalModifiers(modifierListOwner.getModifierList(), Arrays.asList(IN_KEYWORD, OUT_KEYWORD, REIFIED_KEYWORD));
if (!(modifierListOwner instanceof JetTypeParameterListOwner)) return;
List<JetTypeParameter> typeParameters = ((JetTypeParameterListOwner) modifierListOwner).getTypeParameters();
for (JetTypeParameter typeParameter : typeParameters) {
JetModifierList modifierList = typeParameter.getModifierList();
checkIncompatibleVarianceModifiers(modifierList);
}
}
public void checkParameterHasNoModifier(
@NotNull JetParameter parameter
) {
reportIllegalModifiers(parameter.getModifierList(), MODIFIERS_ILLEGAL_ON_PARAMETERS);
}
}
public void checkVarianceModifiers(@NotNull JetModifierListOwner modifierListOwner) {
reportIllegalModifiers(modifierListOwner, Arrays.asList(IN_KEYWORD, OUT_KEYWORD, REIFIED_KEYWORD));
if (!(modifierListOwner instanceof JetTypeParameterListOwner)) return;
List<JetTypeParameter> typeParameters = ((JetTypeParameterListOwner) modifierListOwner).getTypeParameters();
for (JetTypeParameter typeParameter : typeParameters) {
JetModifierList modifierList = typeParameter.getModifierList();
checkIncompatibleVarianceModifiers(modifierList, trace);
}
@NotNull
private final AdditionalCheckerProvider additionalCheckerProvider;
public ModifiersChecker(@NotNull AdditionalCheckerProvider additionalCheckerProvider) {
this.additionalCheckerProvider = additionalCheckerProvider;
}
@NotNull
public ModifiersCheckingProcedure withTrace(@NotNull BindingTrace trace) {
return new ModifiersCheckingProcedure(trace);
}
}
@@ -49,7 +49,8 @@ public class TypeResolver(
private val flexibleTypeCapabilitiesProvider: FlexibleTypeCapabilitiesProvider,
private val storageManager: StorageManager,
private val lazinessToken: TypeLazinessToken,
private val dynamicTypesSettings: DynamicTypesSettings
private val dynamicTypesSettings: DynamicTypesSettings,
private val modifiersChecker: ModifiersChecker
) {
public open class FlexibleTypeCapabilitiesProvider {
@@ -268,9 +269,9 @@ public class TypeResolver(
return argumentElements.mapIndexed { i, argumentElement ->
val projectionKind = argumentElement.getProjectionKind()
ModifiersChecker.checkIncompatibleVarianceModifiers(argumentElement.getModifierList(), c.trace)
modifiersChecker.withTrace(c.trace).checkIncompatibleVarianceModifiers(argumentElement.getModifierList())
if (projectionKind == JetProjectionKind.STAR) {
ModifiersChecker.reportIllegalModifiers(argumentElement.getModifierList(), listOf(JetTokens.IN_KEYWORD, JetTokens.OUT_KEYWORD), c.trace)
modifiersChecker.withTrace(c.trace).reportIllegalModifiers(argumentElement.getModifierList(), listOf(JetTokens.IN_KEYWORD, JetTokens.OUT_KEYWORD))
val parameters = constructor.getParameters()
if (parameters.size() > i) {
@@ -63,7 +63,8 @@ import java.util.ArrayList
public class CandidateResolver(
private val argumentTypeResolver: ArgumentTypeResolver,
private val genericCandidateResolver: GenericCandidateResolver,
private val reflectionTypes: ReflectionTypes
private val reflectionTypes: ReflectionTypes,
private val modifiersChecker: ModifiersChecker
){
public fun <D : CallableDescriptor, F : D> performResolutionForCandidateCall(
@@ -123,7 +124,7 @@ public class CandidateResolver(
for (projection in jetTypeArguments) {
if (projection.getProjectionKind() != JetProjectionKind.NONE) {
trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection))
ModifiersChecker.checkIncompatibleVarianceModifiers(projection.getModifierList(), trace)
modifiersChecker.withTrace(trace).checkIncompatibleVarianceModifiers(projection.getModifierList())
}
val type = argumentTypeResolver.resolveTypeRefWithDefault(
projection.getTypeReference(), scope, trace,
@@ -20,13 +20,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.ClassKind;
import org.jetbrains.kotlin.psi.JetObjectDeclaration;
import org.jetbrains.kotlin.psi.JetParameter;
import org.jetbrains.kotlin.psi.JetTypeParameterList;
import org.jetbrains.kotlin.resolve.ModifiersChecker;
import java.util.Collections;
import java.util.List;
public class JetObjectInfo extends JetClassOrObjectInfo<JetObjectDeclaration> {
@NotNull
private final ClassKind kind;
@@ -49,6 +45,6 @@ public class JetObjectInfo extends JetClassOrObjectInfo<JetObjectDeclaration> {
}
public boolean isCompanionObject() {
return element.isCompanion() && ModifiersChecker.isDefaultModifierAllowed(element);
return element.isCompanion() && ModifiersChecker.isCompanionModifierAllowed(element);
}
}
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.DescriptorResolver;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
@@ -426,7 +423,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetType expectedParameterType,
ExpressionTypingContext context
) {
DescriptorResolver.checkParameterHasNoValOrVar(context.trace, loopParameter, VAL_OR_VAR_ON_LOOP_PARAMETER);
components.modifiersChecker.withTrace(context.trace).checkParameterHasNoValOrVar(loopParameter, VAL_OR_VAR_ON_LOOP_PARAMETER);
JetTypeReference typeReference = loopParameter.getTypeReference();
VariableDescriptor variableDescriptor;
@@ -468,8 +465,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetParameter catchParameter = catchClause.getCatchParameter();
JetExpression catchBody = catchClause.getCatchBody();
if (catchParameter != null) {
DescriptorResolver.checkParameterHasNoValOrVar(context.trace, catchParameter, VAL_OR_VAR_ON_CATCH_PARAMETER);
DescriptorResolver.checkParameterHasNoModifier(context.trace, catchParameter);
ModifiersChecker.ModifiersCheckingProcedure modifiersChecking = components.modifiersChecker.withTrace(context.trace);
modifiersChecking.checkParameterHasNoValOrVar(catchParameter, VAL_OR_VAR_ON_CATCH_PARAMETER);
modifiersChecking.checkParameterHasNoModifier(catchParameter);
VariableDescriptor variableDescriptor = components.descriptorResolver.resolveLocalVariableDescriptor(
context.scope, catchParameter, context.trace);
@@ -51,6 +51,7 @@ public class ExpressionTypingComponents {
/*package*/ ValueParameterResolver valueParameterResolver;
/*package*/ MultiDeclarationResolver multiDeclarationResolver;
/*package*/ ConstantExpressionEvaluator constantExpressionEvaluator;
/*package*/ ModifiersChecker modifiersChecker;
@Inject
public void setGlobalContext(@NotNull GlobalContext globalContext) {
@@ -161,4 +162,9 @@ public class ExpressionTypingComponents {
public void setConstantExpressionEvaluator(@NotNull ConstantExpressionEvaluator constantExpressionEvaluator) {
this.constantExpressionEvaluator = constantExpressionEvaluator;
}
@Inject
public void setModifiersChecker(ModifiersChecker modifiersChecker) {
this.modifiersChecker = modifiersChecker;
}
}
@@ -162,7 +162,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
}
scope.addVariableDescriptor(propertyDescriptor);
ModifiersChecker.create(context.trace, components.additionalCheckerProvider).checkModifiersForLocalDeclaration(property, propertyDescriptor);
components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor);
return typeInfo.replaceType(DataFlowUtils.checkStatementType(property, context));
}
@@ -103,8 +103,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
function.getValueParameters(), functionDescriptor.getValueParameters(), context.scope, context.dataFlowInfo, context.trace
)
ModifiersChecker.create(context.trace, components.additionalCheckerProvider)
.checkModifiersForLocalDeclaration(function, functionDescriptor)
components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(function, functionDescriptor)
if (!function.hasBody()) {
context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
}