001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.resolve; 018 019 import com.google.common.collect.Maps; 020 import com.google.common.collect.Sets; 021 import com.intellij.psi.PsiElement; 022 import org.jetbrains.annotations.NotNull; 023 import org.jetbrains.annotations.Nullable; 024 import org.jetbrains.kotlin.descriptors.*; 025 import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1; 026 import org.jetbrains.kotlin.lexer.KtKeywordToken; 027 import org.jetbrains.kotlin.lexer.KtModifierKeywordToken; 028 import org.jetbrains.kotlin.lexer.KtTokens; 029 import org.jetbrains.kotlin.psi.*; 030 031 import java.util.*; 032 033 import static org.jetbrains.kotlin.diagnostics.Errors.NESTED_CLASS_NOT_ALLOWED; 034 import static org.jetbrains.kotlin.lexer.KtTokens.*; 035 import static org.jetbrains.kotlin.psi.KtStubbedPsiUtil.getContainingDeclaration; 036 037 public class ModifiersChecker { 038 private static final Set<KtModifierKeywordToken> MODIFIERS_ILLEGAL_ON_PARAMETERS; 039 040 static { 041 MODIFIERS_ILLEGAL_ON_PARAMETERS = Sets.newHashSet(); 042 MODIFIERS_ILLEGAL_ON_PARAMETERS.addAll(Arrays.asList(KtTokens.MODIFIER_KEYWORDS_ARRAY)); 043 MODIFIERS_ILLEGAL_ON_PARAMETERS.remove(KtTokens.VARARG_KEYWORD); 044 } 045 046 public static boolean isIllegalInner(@NotNull DeclarationDescriptor descriptor) { 047 return checkIllegalInner(descriptor) != InnerModifierCheckResult.ALLOWED; 048 } 049 050 private enum InnerModifierCheckResult { 051 ALLOWED, 052 ILLEGAL_POSITION, 053 IN_INTERFACE, 054 IN_OBJECT, 055 } 056 057 058 // NOTE: just checks if this is legal context for companion modifier (Companion object descriptor can be created) 059 // COMPANION_OBJECT_NOT_ALLOWED can be reported later 060 public static boolean isCompanionModifierAllowed(@NotNull KtDeclaration declaration) { 061 if (declaration instanceof KtObjectDeclaration) { 062 KtDeclaration containingDeclaration = getContainingDeclaration(declaration); 063 if (containingDeclaration instanceof KtClassOrObject) { 064 return true; 065 } 066 } 067 return false; 068 } 069 070 @NotNull 071 private static InnerModifierCheckResult checkIllegalInner(@NotNull DeclarationDescriptor descriptor) { 072 if (!(descriptor instanceof ClassDescriptor)) return InnerModifierCheckResult.ILLEGAL_POSITION; 073 ClassDescriptor classDescriptor = (ClassDescriptor) descriptor; 074 075 if (classDescriptor.getKind() != ClassKind.CLASS) return InnerModifierCheckResult.ILLEGAL_POSITION; 076 077 DeclarationDescriptor containingDeclaration = classDescriptor.getContainingDeclaration(); 078 if (!(containingDeclaration instanceof ClassDescriptor)) return InnerModifierCheckResult.ILLEGAL_POSITION; 079 080 if (DescriptorUtils.isInterface(containingDeclaration)) { 081 return InnerModifierCheckResult.IN_INTERFACE; 082 } 083 else if (DescriptorUtils.isObject(containingDeclaration)) { 084 return InnerModifierCheckResult.IN_OBJECT; 085 } 086 else { 087 return InnerModifierCheckResult.ALLOWED; 088 } 089 } 090 091 private static boolean isIllegalNestedClass(@NotNull DeclarationDescriptor descriptor) { 092 if (!(descriptor instanceof ClassDescriptor)) return false; 093 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 094 if (!(containingDeclaration instanceof ClassDescriptor)) return false; 095 ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration; 096 return containingClass.isInner() || containingClass.getContainingDeclaration() instanceof FunctionDescriptor; 097 } 098 099 @NotNull 100 public static Modality resolveModalityFromModifiers( 101 @NotNull KtModifierListOwner modifierListOwner, 102 @NotNull Modality defaultModality 103 ) { 104 return resolveModalityFromModifiers(modifierListOwner.getModifierList(), defaultModality); 105 } 106 107 @NotNull 108 public static Modality resolveModalityFromModifiers(@Nullable KtModifierList modifierList, @NotNull Modality defaultModality) { 109 if (modifierList == null) return defaultModality; 110 boolean hasAbstractModifier = modifierList.hasModifier(ABSTRACT_KEYWORD); 111 boolean hasOverrideModifier = modifierList.hasModifier(OVERRIDE_KEYWORD); 112 113 if (modifierList.hasModifier(SEALED_KEYWORD)) { 114 return Modality.SEALED; 115 } 116 if (modifierList.hasModifier(OPEN_KEYWORD)) { 117 if (hasAbstractModifier || defaultModality == Modality.ABSTRACT) { 118 return Modality.ABSTRACT; 119 } 120 return Modality.OPEN; 121 } 122 if (hasAbstractModifier) { 123 return Modality.ABSTRACT; 124 } 125 boolean hasFinalModifier = modifierList.hasModifier(FINAL_KEYWORD); 126 if (hasOverrideModifier && !hasFinalModifier && !(defaultModality == Modality.ABSTRACT)) { 127 return Modality.OPEN; 128 } 129 if (hasFinalModifier) { 130 return Modality.FINAL; 131 } 132 return defaultModality; 133 } 134 135 @NotNull 136 public static Visibility resolveVisibilityFromModifiers( 137 @NotNull KtModifierListOwner modifierListOwner, 138 @NotNull Visibility defaultVisibility 139 ) { 140 return resolveVisibilityFromModifiers(modifierListOwner.getModifierList(), defaultVisibility); 141 } 142 143 public static Visibility resolveVisibilityFromModifiers(@Nullable KtModifierList modifierList, @NotNull Visibility defaultVisibility) { 144 if (modifierList == null) return defaultVisibility; 145 if (modifierList.hasModifier(PRIVATE_KEYWORD)) return Visibilities.PRIVATE; 146 if (modifierList.hasModifier(PUBLIC_KEYWORD)) return Visibilities.PUBLIC; 147 if (modifierList.hasModifier(PROTECTED_KEYWORD)) return Visibilities.PROTECTED; 148 if (modifierList.hasModifier(INTERNAL_KEYWORD)) return Visibilities.INTERNAL; 149 return defaultVisibility; 150 } 151 152 public static boolean isInnerClass(@Nullable KtModifierList modifierList) { 153 return modifierList != null && modifierList.hasModifier(INNER_KEYWORD); 154 } 155 156 public class ModifiersCheckingProcedure { 157 158 @NotNull 159 private final BindingTrace trace; 160 161 private ModifiersCheckingProcedure(@NotNull BindingTrace trace) { 162 this.trace = trace; 163 } 164 165 public void checkParameterHasNoValOrVar( 166 @NotNull KtValVarKeywordOwner parameter, 167 @NotNull DiagnosticFactory1<PsiElement, KtKeywordToken> diagnosticFactory 168 ) { 169 PsiElement valOrVar = parameter.getValOrVarKeyword(); 170 if (valOrVar != null) { 171 trace.report(diagnosticFactory.on(valOrVar, ((KtKeywordToken) valOrVar.getNode().getElementType()))); 172 } 173 } 174 175 public void checkModifiersForDeclaration(@NotNull KtDeclaration modifierListOwner, @NotNull MemberDescriptor descriptor) { 176 checkNestedClassAllowed(modifierListOwner, descriptor); 177 checkTypeParametersModifiers(modifierListOwner); 178 checkModifierListCommon(modifierListOwner, descriptor); 179 } 180 181 private void checkModifierListCommon(@NotNull KtDeclaration modifierListOwner, @NotNull DeclarationDescriptor descriptor) { 182 AnnotationUseSiteTargetChecker.INSTANCE.check(modifierListOwner, descriptor, trace); 183 runDeclarationCheckers(modifierListOwner, descriptor); 184 annotationChecker.check(modifierListOwner, trace, descriptor); 185 ModifierCheckerCore.INSTANCE.check(modifierListOwner, trace, descriptor); 186 } 187 188 public void checkModifiersForLocalDeclaration( 189 @NotNull KtDeclaration modifierListOwner, 190 @NotNull DeclarationDescriptor descriptor 191 ) { 192 checkModifierListCommon(modifierListOwner, descriptor); 193 } 194 195 public void checkModifiersForDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration) { 196 annotationChecker.check(multiDeclaration, trace, null); 197 ModifierCheckerCore.INSTANCE.check(multiDeclaration, trace, null); 198 for (KtDestructuringDeclarationEntry multiEntry: multiDeclaration.getEntries()) { 199 annotationChecker.check(multiEntry, trace, null); 200 ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null); 201 UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace); 202 } 203 } 204 205 private void checkNestedClassAllowed(@NotNull KtModifierListOwner modifierListOwner, @NotNull DeclarationDescriptor descriptor) { 206 if (modifierListOwner.hasModifier(INNER_KEYWORD)) return; 207 if (modifierListOwner instanceof KtClass && !(modifierListOwner instanceof KtEnumEntry)) { 208 KtClass aClass = (KtClass) modifierListOwner; 209 boolean localEnumError = aClass.isLocal() && aClass.isEnum(); 210 if (!localEnumError && isIllegalNestedClass(descriptor)) { 211 trace.report(NESTED_CLASS_NOT_ALLOWED.on(aClass)); 212 } 213 } 214 } 215 216 @NotNull 217 public Map<KtModifierKeywordToken, PsiElement> getTokensCorrespondingToModifiers( 218 @NotNull KtModifierList modifierList, 219 @NotNull Collection<KtModifierKeywordToken> possibleModifiers 220 ) { 221 Map<KtModifierKeywordToken, PsiElement> tokens = Maps.newHashMap(); 222 for (KtModifierKeywordToken modifier : possibleModifiers) { 223 if (modifierList.hasModifier(modifier)) { 224 tokens.put(modifier, modifierList.getModifier(modifier)); 225 } 226 } 227 return tokens; 228 } 229 230 231 public void runDeclarationCheckers( 232 @NotNull KtDeclaration declaration, 233 @NotNull DeclarationDescriptor descriptor 234 ) { 235 for (DeclarationChecker checker : declarationCheckers) { 236 checker.check(declaration, descriptor, trace, trace.getBindingContext()); 237 } 238 } 239 240 public void checkTypeParametersModifiers(@NotNull KtModifierListOwner modifierListOwner) { 241 if (!(modifierListOwner instanceof KtTypeParameterListOwner)) return; 242 List<KtTypeParameter> typeParameters = ((KtTypeParameterListOwner) modifierListOwner).getTypeParameters(); 243 for (KtTypeParameter typeParameter : typeParameters) { 244 ModifierCheckerCore.INSTANCE.check(typeParameter, trace, null); 245 } 246 } 247 } 248 249 @NotNull 250 private final AnnotationChecker annotationChecker; 251 252 @NotNull 253 private final Iterable<DeclarationChecker> declarationCheckers; 254 255 public ModifiersChecker(@NotNull AnnotationChecker annotationChecker, @NotNull Iterable<DeclarationChecker> declarationCheckers) { 256 this.annotationChecker = annotationChecker; 257 this.declarationCheckers = declarationCheckers; 258 } 259 260 @NotNull 261 public ModifiersCheckingProcedure withTrace(@NotNull BindingTrace trace) { 262 return new ModifiersCheckingProcedure(trace); 263 } 264 }