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.Lists; 020 import com.google.common.collect.Maps; 021 import com.google.common.collect.Sets; 022 import com.intellij.psi.PsiElement; 023 import org.jetbrains.annotations.NotNull; 024 import org.jetbrains.annotations.Nullable; 025 import org.jetbrains.kotlin.descriptors.*; 026 import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1; 027 import org.jetbrains.kotlin.lexer.JetKeywordToken; 028 import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; 029 import org.jetbrains.kotlin.lexer.JetTokens; 030 import org.jetbrains.kotlin.psi.*; 031 032 import java.util.*; 033 034 import static org.jetbrains.kotlin.diagnostics.Errors.NESTED_CLASS_NOT_ALLOWED; 035 import static org.jetbrains.kotlin.lexer.JetTokens.*; 036 import static org.jetbrains.kotlin.psi.JetStubbedPsiUtil.getContainingDeclaration; 037 038 public class ModifiersChecker { 039 private static final Set<JetModifierKeywordToken> MODIFIERS_ILLEGAL_ON_PARAMETERS; 040 041 static { 042 MODIFIERS_ILLEGAL_ON_PARAMETERS = Sets.newHashSet(); 043 MODIFIERS_ILLEGAL_ON_PARAMETERS.addAll(Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY)); 044 MODIFIERS_ILLEGAL_ON_PARAMETERS.remove(JetTokens.VARARG_KEYWORD); 045 } 046 047 public static boolean isIllegalInner(@NotNull DeclarationDescriptor descriptor) { 048 return checkIllegalInner(descriptor) != InnerModifierCheckResult.ALLOWED; 049 } 050 051 private enum InnerModifierCheckResult { 052 ALLOWED, 053 ILLEGAL_POSITION, 054 IN_TRAIT, 055 IN_OBJECT, 056 } 057 058 059 // NOTE: just checks if this is legal context for companion modifier (Companion object descriptor can be created) 060 // COMPANION_OBJECT_NOT_ALLOWED can be reported later 061 public static boolean isCompanionModifierAllowed(@NotNull JetDeclaration declaration) { 062 if (declaration instanceof JetObjectDeclaration) { 063 JetDeclaration containingDeclaration = getContainingDeclaration(declaration); 064 if (containingDeclaration instanceof JetClassOrObject) { 065 return true; 066 } 067 } 068 return false; 069 } 070 071 @NotNull 072 private static InnerModifierCheckResult checkIllegalInner(@NotNull DeclarationDescriptor descriptor) { 073 if (!(descriptor instanceof ClassDescriptor)) return InnerModifierCheckResult.ILLEGAL_POSITION; 074 ClassDescriptor classDescriptor = (ClassDescriptor) descriptor; 075 076 if (classDescriptor.getKind() != ClassKind.CLASS) return InnerModifierCheckResult.ILLEGAL_POSITION; 077 078 DeclarationDescriptor containingDeclaration = classDescriptor.getContainingDeclaration(); 079 if (!(containingDeclaration instanceof ClassDescriptor)) return InnerModifierCheckResult.ILLEGAL_POSITION; 080 081 if (DescriptorUtils.isTrait(containingDeclaration)) { 082 return InnerModifierCheckResult.IN_TRAIT; 083 } 084 else if (DescriptorUtils.isObject(containingDeclaration)) { 085 return InnerModifierCheckResult.IN_OBJECT; 086 } 087 else { 088 return InnerModifierCheckResult.ALLOWED; 089 } 090 } 091 092 private static boolean isIllegalNestedClass(@NotNull DeclarationDescriptor descriptor) { 093 if (!(descriptor instanceof ClassDescriptor)) return false; 094 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 095 if (!(containingDeclaration instanceof ClassDescriptor)) return false; 096 ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration; 097 return containingClass.isInner() || containingClass.getContainingDeclaration() instanceof FunctionDescriptor; 098 } 099 100 @NotNull 101 public static Modality resolveModalityFromModifiers( 102 @NotNull JetModifierListOwner modifierListOwner, 103 @NotNull Modality defaultModality 104 ) { 105 return resolveModalityFromModifiers(modifierListOwner.getModifierList(), defaultModality); 106 } 107 108 @NotNull 109 public static Modality resolveModalityFromModifiers(@Nullable JetModifierList modifierList, @NotNull Modality defaultModality) { 110 if (modifierList == null) return defaultModality; 111 boolean hasAbstractModifier = modifierList.hasModifier(ABSTRACT_KEYWORD); 112 boolean hasOverrideModifier = modifierList.hasModifier(OVERRIDE_KEYWORD); 113 114 if (modifierList.hasModifier(SEALED_KEYWORD)) { 115 return Modality.SEALED; 116 } 117 if (modifierList.hasModifier(OPEN_KEYWORD)) { 118 if (hasAbstractModifier || defaultModality == Modality.ABSTRACT) { 119 return Modality.ABSTRACT; 120 } 121 return Modality.OPEN; 122 } 123 if (hasAbstractModifier) { 124 return Modality.ABSTRACT; 125 } 126 boolean hasFinalModifier = modifierList.hasModifier(FINAL_KEYWORD); 127 if (hasOverrideModifier && !hasFinalModifier && !(defaultModality == Modality.ABSTRACT)) { 128 return Modality.OPEN; 129 } 130 if (hasFinalModifier) { 131 return Modality.FINAL; 132 } 133 return defaultModality; 134 } 135 136 @NotNull 137 public static Visibility resolveVisibilityFromModifiers( 138 @NotNull JetModifierListOwner modifierListOwner, 139 @NotNull Visibility defaultVisibility 140 ) { 141 return resolveVisibilityFromModifiers(modifierListOwner.getModifierList(), defaultVisibility); 142 } 143 144 public static Visibility resolveVisibilityFromModifiers(@Nullable JetModifierList modifierList, @NotNull Visibility defaultVisibility) { 145 if (modifierList == null) return defaultVisibility; 146 if (modifierList.hasModifier(PRIVATE_KEYWORD)) return Visibilities.PRIVATE; 147 if (modifierList.hasModifier(PUBLIC_KEYWORD)) return Visibilities.PUBLIC; 148 if (modifierList.hasModifier(PROTECTED_KEYWORD)) return Visibilities.PROTECTED; 149 if (modifierList.hasModifier(INTERNAL_KEYWORD)) return Visibilities.INTERNAL; 150 return defaultVisibility; 151 } 152 153 public static boolean isInnerClass(@Nullable JetModifierList modifierList) { 154 return modifierList != null && modifierList.hasModifier(INNER_KEYWORD); 155 } 156 157 public class ModifiersCheckingProcedure { 158 159 @NotNull 160 private final BindingTrace trace; 161 162 private ModifiersCheckingProcedure(@NotNull BindingTrace trace) { 163 this.trace = trace; 164 } 165 166 public void checkParameterHasNoValOrVar( 167 @NotNull JetParameter parameter, 168 @NotNull DiagnosticFactory1<PsiElement, JetKeywordToken> diagnosticFactory 169 ) { 170 PsiElement valOrVar = parameter.getValOrVarKeyword(); 171 if (valOrVar != null) { 172 trace.report(diagnosticFactory.on(valOrVar, ((JetKeywordToken) valOrVar.getNode().getElementType()))); 173 } 174 } 175 176 public void checkModifiersForDeclaration(@NotNull JetDeclaration modifierListOwner, @NotNull MemberDescriptor descriptor) { 177 checkNestedClassAllowed(modifierListOwner, descriptor); 178 checkTypeParametersModifiers(modifierListOwner); 179 checkModifierListCommon(modifierListOwner, descriptor); 180 } 181 182 private void checkModifierListCommon(@NotNull JetDeclaration modifierListOwner, @NotNull DeclarationDescriptor descriptor) { 183 AnnotationUseSiteTargetChecker.INSTANCE$.check(modifierListOwner, descriptor, trace); 184 runDeclarationCheckers(modifierListOwner, descriptor); 185 ClassDescriptor classDescriptor = descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null; 186 annotationChecker.check(modifierListOwner, trace, classDescriptor); 187 ModifierCheckerCore.INSTANCE$.check(modifierListOwner, trace, descriptor); 188 } 189 190 public void checkModifiersForLocalDeclaration( 191 @NotNull JetDeclaration modifierListOwner, 192 @NotNull DeclarationDescriptor descriptor 193 ) { 194 checkModifierListCommon(modifierListOwner, descriptor); 195 } 196 197 public void checkModifiersForMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration) { 198 annotationChecker.check(multiDeclaration, trace, null); 199 ModifierCheckerCore.INSTANCE$.check(multiDeclaration, trace, null); 200 for (JetMultiDeclarationEntry multiEntry: multiDeclaration.getEntries()) { 201 annotationChecker.check(multiEntry, trace, null); 202 ModifierCheckerCore.INSTANCE$.check(multiEntry, trace, null); 203 UnderscoreChecker.INSTANCE$.checkNamed(multiEntry, trace); 204 } 205 } 206 207 private void checkNestedClassAllowed(@NotNull JetModifierListOwner modifierListOwner, @NotNull DeclarationDescriptor descriptor) { 208 if (modifierListOwner.hasModifier(INNER_KEYWORD)) return; 209 if (modifierListOwner instanceof JetClass && !(modifierListOwner instanceof JetEnumEntry)) { 210 JetClass aClass = (JetClass) modifierListOwner; 211 boolean localEnumError = aClass.isLocal() && aClass.isEnum(); 212 if (!localEnumError && isIllegalNestedClass(descriptor)) { 213 trace.report(NESTED_CLASS_NOT_ALLOWED.on(aClass)); 214 } 215 } 216 } 217 218 @NotNull 219 public Map<JetModifierKeywordToken, PsiElement> getTokensCorrespondingToModifiers( 220 @NotNull JetModifierList modifierList, 221 @NotNull Collection<JetModifierKeywordToken> possibleModifiers 222 ) { 223 Map<JetModifierKeywordToken, PsiElement> tokens = Maps.newHashMap(); 224 for (JetModifierKeywordToken modifier : possibleModifiers) { 225 if (modifierList.hasModifier(modifier)) { 226 tokens.put(modifier, modifierList.getModifier(modifier)); 227 } 228 } 229 return tokens; 230 } 231 232 233 private void runDeclarationCheckers(@NotNull JetDeclaration declaration, @NotNull DeclarationDescriptor descriptor) { 234 for (DeclarationChecker checker : declarationCheckers) { 235 checker.check(declaration, descriptor, trace, trace.getBindingContext()); 236 } 237 } 238 239 public void checkTypeParametersModifiers(@NotNull JetModifierListOwner modifierListOwner) { 240 if (!(modifierListOwner instanceof JetTypeParameterListOwner)) return; 241 List<JetTypeParameter> typeParameters = ((JetTypeParameterListOwner) modifierListOwner).getTypeParameters(); 242 for (JetTypeParameter typeParameter : typeParameters) { 243 ModifierCheckerCore.INSTANCE$.check(typeParameter, trace, null); 244 } 245 } 246 } 247 248 @NotNull 249 private final AnnotationChecker annotationChecker; 250 251 @NotNull 252 private final Iterable<DeclarationChecker> declarationCheckers; 253 254 public ModifiersChecker(@NotNull AnnotationChecker annotationChecker, @NotNull Iterable<DeclarationChecker> declarationCheckers) { 255 this.annotationChecker = annotationChecker; 256 this.declarationCheckers = declarationCheckers; 257 } 258 259 @NotNull 260 public ModifiersCheckingProcedure withTrace(@NotNull BindingTrace trace) { 261 return new ModifiersCheckingProcedure(trace); 262 } 263 }