001/* 002 * Copyright 2010-2013 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 017package org.jetbrains.jet.lang.resolve.scopes; 018 019import com.google.common.collect.*; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.descriptors.*; 023import org.jetbrains.jet.lang.resolve.name.LabelName; 024import org.jetbrains.jet.lang.resolve.name.Name; 025import org.jetbrains.jet.lang.types.checker.JetTypeChecker; 026import org.jetbrains.jet.util.CommonSuppliers; 027 028import java.util.*; 029 030public class WritableScopeImpl extends WritableScopeWithImports { 031 032 private final Collection<DeclarationDescriptor> allDescriptors = Lists.newArrayList(); 033 private final Multimap<Name, DeclarationDescriptor> declaredDescriptorsAccessibleBySimpleName = HashMultimap.create(); 034 private boolean allDescriptorsDone = false; 035 036 private Set<ClassDescriptor> allObjectDescriptors = null; 037 038 @NotNull 039 private final DeclarationDescriptor ownerDeclarationDescriptor; 040 041 // FieldNames include "$" 042 @Nullable 043 private Map<Name, PropertyDescriptor> propertyDescriptorsByFieldNames; 044 045 @Nullable 046 private SetMultimap<Name, FunctionDescriptor> functionGroups; 047 048 @Nullable 049 private Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors; 050 051 @Nullable 052 private SetMultimap<Name, VariableDescriptor> propertyGroups; 053 054 @Nullable 055 private Map<Name, NamespaceDescriptor> namespaceAliases; 056 057 @Nullable 058 private Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors; 059 060 @Nullable 061 private Map<Name, ClassDescriptor> objectDescriptors; 062 063 @Nullable 064 private ReceiverParameterDescriptor implicitReceiver; 065 066 public WritableScopeImpl(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner, 067 @NotNull RedeclarationHandler redeclarationHandler, @NotNull String debugName) { 068 super(scope, redeclarationHandler, debugName); 069 this.ownerDeclarationDescriptor = owner; 070 } 071 072 @NotNull 073 @Override 074 public DeclarationDescriptor getContainingDeclaration() { 075 return ownerDeclarationDescriptor; 076 } 077 078 @Override 079 public void importScope(@NotNull JetScope imported) { 080 checkMayWrite(); 081 super.importScope(imported); 082 } 083 084 @Override 085 public void importClassifierAlias(@NotNull Name importedClassifierName, @NotNull ClassifierDescriptor classifierDescriptor) { 086 checkMayWrite(); 087 088 allDescriptors.add(classifierDescriptor); 089 super.importClassifierAlias(importedClassifierName, classifierDescriptor); 090 } 091 092 @Override 093 public void importNamespaceAlias(@NotNull Name aliasName, @NotNull NamespaceDescriptor namespaceDescriptor) { 094 checkMayWrite(); 095 096 allDescriptors.add(namespaceDescriptor); 097 super.importNamespaceAlias(aliasName, namespaceDescriptor); 098 } 099 100 @Override 101 public void importFunctionAlias(@NotNull Name aliasName, @NotNull FunctionDescriptor functionDescriptor) { 102 checkMayWrite(); 103 104 addFunctionDescriptor(functionDescriptor); 105 super.importFunctionAlias(aliasName, functionDescriptor); 106 107 } 108 109 @Override 110 public void importVariableAlias(@NotNull Name aliasName, @NotNull VariableDescriptor variableDescriptor) { 111 checkMayWrite(); 112 113 addPropertyDescriptor(variableDescriptor); 114 super.importVariableAlias(aliasName, variableDescriptor); 115 } 116 117 @Override 118 public void clearImports() { 119 checkMayWrite(); 120 121 super.clearImports(); 122 } 123 124 @NotNull 125 @Override 126 public Collection<DeclarationDescriptor> getAllDescriptors() { 127 checkMayRead(); 128 129 if (!allDescriptorsDone) { 130 allDescriptorsDone = true; 131 132 // make sure no descriptors added to allDescriptors collection 133 changeLockLevel(LockLevel.READING); 134 135 allDescriptors.addAll(getWorkerScope().getAllDescriptors()); 136 for (JetScope imported : getImports()) { 137 allDescriptors.addAll(imported.getAllDescriptors()); 138 } 139 } 140 return allDescriptors; 141 } 142 143 @NotNull 144 private Map<LabelName, List<DeclarationDescriptor>> getLabelsToDescriptors() { 145 if (labelsToDescriptors == null) { 146 labelsToDescriptors = new HashMap<LabelName, List<DeclarationDescriptor>>(); 147 } 148 return labelsToDescriptors; 149 } 150 151 @NotNull 152 private Map<Name, ClassDescriptor> getObjectDescriptorsMap() { 153 if (objectDescriptors == null) { 154 objectDescriptors = Maps.newHashMap(); 155 } 156 return objectDescriptors; 157 } 158 159 @NotNull 160 @Override 161 public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) { 162 checkMayRead(); 163 164 Collection<DeclarationDescriptor> superResult = super.getDeclarationsByLabel(labelName); 165 Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors(); 166 List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(labelName); 167 if (declarationDescriptors == null) { 168 return superResult; 169 } 170 if (superResult.isEmpty()) return declarationDescriptors; 171 List<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>(declarationDescriptors); 172 result.addAll(superResult); 173 return result; 174 } 175 176 @Override 177 public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) { 178 checkMayWrite(); 179 180 Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors(); 181 LabelName name = new LabelName(descriptor.getName().asString()); 182 List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(name); 183 if (declarationDescriptors == null) { 184 declarationDescriptors = new ArrayList<DeclarationDescriptor>(); 185 labelsToDescriptors.put(name, declarationDescriptors); 186 } 187 declarationDescriptors.add(descriptor); 188 } 189 190 @NotNull 191 private Map<Name, DeclarationDescriptor> getVariableClassOrNamespaceDescriptors() { 192 if (variableClassOrNamespaceDescriptors == null) { 193 variableClassOrNamespaceDescriptors = Maps.newHashMap(); 194 } 195 return variableClassOrNamespaceDescriptors; 196 } 197 198 @NotNull 199 private Map<Name, NamespaceDescriptor> getNamespaceAliases() { 200 if (namespaceAliases == null) { 201 namespaceAliases = Maps.newHashMap(); 202 } 203 return namespaceAliases; 204 } 205 206 @Override 207 public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) { 208 addVariableDescriptor(variableDescriptor, false); 209 } 210 211 @Override 212 public void addPropertyDescriptor(@NotNull VariableDescriptor propertyDescriptor) { 213 addVariableDescriptor(propertyDescriptor, true); 214 } 215 216 private void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor, boolean isProperty) { 217 checkMayWrite(); 218 219 Name name = variableDescriptor.getName(); 220 if (isProperty) { 221 checkForPropertyRedeclaration(name, variableDescriptor); 222 getPropertyGroups().put(name, variableDescriptor); 223 } 224 if (variableDescriptor.getReceiverParameter() == null) { 225 checkForRedeclaration(name, variableDescriptor); 226 // TODO : Should this always happen? 227 getVariableClassOrNamespaceDescriptors().put(name, variableDescriptor); 228 } 229 allDescriptors.add(variableDescriptor); 230 addToDeclared(variableDescriptor); 231 } 232 233 @NotNull 234 @Override 235 public Set<VariableDescriptor> getProperties(@NotNull Name name) { 236 checkMayRead(); 237 238 Set<VariableDescriptor> result = Sets.newLinkedHashSet(getPropertyGroups().get(name)); 239 240 result.addAll(getWorkerScope().getProperties(name)); 241 242 result.addAll(super.getProperties(name)); 243 244 return result; 245 } 246 247 @Override 248 public VariableDescriptor getLocalVariable(@NotNull Name name) { 249 checkMayRead(); 250 251 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); 252 DeclarationDescriptor descriptor = variableClassOrNamespaceDescriptors.get(name); 253 if (descriptor instanceof VariableDescriptor && !getPropertyGroups().get(name).contains(descriptor)) { 254 return (VariableDescriptor) descriptor; 255 } 256 257 VariableDescriptor variableDescriptor = getWorkerScope().getLocalVariable(name); 258 if (variableDescriptor != null) { 259 return variableDescriptor; 260 } 261 return super.getLocalVariable(name); 262 } 263 264 @NotNull 265 private SetMultimap<Name, VariableDescriptor> getPropertyGroups() { 266 if (propertyGroups == null) { 267 propertyGroups = CommonSuppliers.newLinkedHashSetHashSetMultimap(); 268 } 269 return propertyGroups; 270 } 271 272 @NotNull 273 private SetMultimap<Name, FunctionDescriptor> getFunctionGroups() { 274 if (functionGroups == null) { 275 functionGroups = CommonSuppliers.newLinkedHashSetHashSetMultimap(); 276 } 277 return functionGroups; 278 } 279 280 @Override 281 public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { 282 checkMayWrite(); 283 284 getFunctionGroups().put(functionDescriptor.getName(), functionDescriptor); 285 allDescriptors.add(functionDescriptor); 286 } 287 288 @Override 289 @NotNull 290 public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) { 291 checkMayRead(); 292 293 Set<FunctionDescriptor> result = Sets.newLinkedHashSet(getFunctionGroups().get(name)); 294 295 result.addAll(getWorkerScope().getFunctions(name)); 296 297 result.addAll(super.getFunctions(name)); 298 299 return result; 300 } 301 302 @Override 303 public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) { 304 checkMayWrite(); 305 306 Name name = typeParameterDescriptor.getName(); 307 addClassifierAlias(name, typeParameterDescriptor); 308 } 309 310 @Override 311 public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) { 312 checkMayWrite(); 313 314 if (isObject(classDescriptor)) { 315 throw new IllegalStateException("must not be object: " + classDescriptor); 316 } 317 318 addClassifierAlias(classDescriptor.getName(), classDescriptor); 319 } 320 321 @Override 322 public void addObjectDescriptor(@NotNull ClassDescriptor objectDescriptor) { 323 checkMayWrite(); 324 325 if (!objectDescriptor.getKind().isObject()) { 326 throw new IllegalStateException("must be object: " + objectDescriptor); 327 } 328 329 getObjectDescriptorsMap().put(objectDescriptor.getName(), objectDescriptor); 330 } 331 332 @Override 333 public void addClassifierAlias(@NotNull Name name, @NotNull ClassifierDescriptor classifierDescriptor) { 334 checkMayWrite(); 335 336 checkForRedeclaration(name, classifierDescriptor); 337 getVariableClassOrNamespaceDescriptors().put(name, classifierDescriptor); 338 allDescriptors.add(classifierDescriptor); 339 addToDeclared(classifierDescriptor); 340 } 341 342 @Override 343 public void addNamespaceAlias(@NotNull Name name, @NotNull NamespaceDescriptor namespaceDescriptor) { 344 checkMayWrite(); 345 346 checkForRedeclaration(name, namespaceDescriptor); 347 getNamespaceAliases().put(name, namespaceDescriptor); 348 allDescriptors.add(namespaceDescriptor); 349 addToDeclared(namespaceDescriptor); 350 } 351 352 @Override 353 public void addFunctionAlias(@NotNull Name name, @NotNull FunctionDescriptor functionDescriptor) { 354 checkMayWrite(); 355 356 checkForRedeclaration(name, functionDescriptor); 357 getFunctionGroups().put(name, functionDescriptor); 358 allDescriptors.add(functionDescriptor); 359 } 360 361 @Override 362 public void addVariableAlias(@NotNull Name name, @NotNull VariableDescriptor variableDescriptor) { 363 checkMayWrite(); 364 365 checkForRedeclaration(name, variableDescriptor); 366 getVariableClassOrNamespaceDescriptors().put(name, variableDescriptor); 367 allDescriptors.add(variableDescriptor); 368 addToDeclared(variableDescriptor); 369 } 370 371 private void checkForPropertyRedeclaration(@NotNull Name name, VariableDescriptor variableDescriptor) { 372 Set<VariableDescriptor> properties = getPropertyGroups().get(name); 373 ReceiverParameterDescriptor receiverParameter = variableDescriptor.getReceiverParameter(); 374 for (VariableDescriptor oldProperty : properties) { 375 ReceiverParameterDescriptor receiverParameterForOldVariable = oldProperty.getReceiverParameter(); 376 if (((receiverParameter != null && receiverParameterForOldVariable != null) && 377 (JetTypeChecker.INSTANCE.equalTypes(receiverParameter.getType(), receiverParameterForOldVariable.getType())))) { 378 redeclarationHandler.handleRedeclaration(oldProperty, variableDescriptor); 379 } 380 } 381 } 382 383 private void checkForRedeclaration(@NotNull Name name, DeclarationDescriptor classifierDescriptor) { 384 DeclarationDescriptor originalDescriptor = getVariableClassOrNamespaceDescriptors().get(name); 385 if (originalDescriptor != null) { 386 redeclarationHandler.handleRedeclaration(originalDescriptor, classifierDescriptor); 387 } 388 } 389 390 @Override 391 public ClassifierDescriptor getClassifier(@NotNull Name name) { 392 checkMayRead(); 393 394 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); 395 DeclarationDescriptor descriptor = variableClassOrNamespaceDescriptors.get(name); 396 if (descriptor instanceof ClassifierDescriptor) return (ClassifierDescriptor) descriptor; 397 398 ClassifierDescriptor classifierDescriptor = getWorkerScope().getClassifier(name); 399 if (classifierDescriptor != null) return classifierDescriptor; 400 401 return super.getClassifier(name); 402 } 403 404 @Override 405 public ClassDescriptor getObjectDescriptor(@NotNull Name name) { 406 ClassDescriptor descriptor = getObjectDescriptorsMap().get(name); 407 if (descriptor != null) return descriptor; 408 409 ClassDescriptor fromWorker = getWorkerScope().getObjectDescriptor(name); 410 if (fromWorker != null) return fromWorker; 411 412 return super.getObjectDescriptor(name); 413 } 414 415 @NotNull 416 @Override 417 public Set<ClassDescriptor> getObjectDescriptors() { 418 if (allObjectDescriptors == null) { 419 allObjectDescriptors = Sets.newHashSet(getObjectDescriptorsMap().values()); 420 allObjectDescriptors.addAll(getWorkerScope().getObjectDescriptors()); 421 for (JetScope imported : getImports()) { 422 allObjectDescriptors.addAll(imported.getObjectDescriptors()); 423 } 424 } 425 return allObjectDescriptors; 426 } 427 428 @Override 429 public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { 430 checkMayWrite(); 431 432 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); 433 DeclarationDescriptor oldValue = variableClassOrNamespaceDescriptors.put(namespaceDescriptor.getName(), namespaceDescriptor); 434 if (oldValue != null) { 435 redeclarationHandler.handleRedeclaration(oldValue, namespaceDescriptor); 436 } 437 allDescriptors.add(namespaceDescriptor); 438 addToDeclared(namespaceDescriptor); 439 } 440 441 @Override 442 public NamespaceDescriptor getDeclaredNamespace(@NotNull Name name) { 443 checkMayRead(); 444 445 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); 446 DeclarationDescriptor namespaceDescriptor = variableClassOrNamespaceDescriptors.get(name); 447 if (namespaceDescriptor instanceof NamespaceDescriptor) return (NamespaceDescriptor) namespaceDescriptor; 448 return null; 449 } 450 451 @Override 452 public NamespaceDescriptor getNamespace(@NotNull Name name) { 453 checkMayRead(); 454 455 NamespaceDescriptor declaredNamespace = getDeclaredNamespace(name); 456 if (declaredNamespace != null) return declaredNamespace; 457 458 NamespaceDescriptor aliased = getNamespaceAliases().get(name); 459 if (aliased != null) return aliased; 460 461 NamespaceDescriptor namespace = getWorkerScope().getNamespace(name); 462 if (namespace != null) return namespace; 463 return super.getNamespace(name); 464 } 465 466 @Override 467 public void setImplicitReceiver(@NotNull ReceiverParameterDescriptor implicitReceiver) { 468 checkMayWrite(); 469 470 if (this.implicitReceiver != null) { 471 throw new UnsupportedOperationException("Receiver redeclared"); 472 } 473 this.implicitReceiver = implicitReceiver; 474 } 475 476 @Override 477 protected List<ReceiverParameterDescriptor> computeImplicitReceiversHierarchy() { 478 List<ReceiverParameterDescriptor> implicitReceiverHierarchy = Lists.newArrayList(); 479 if (implicitReceiver != null) { 480 implicitReceiverHierarchy.add(implicitReceiver); 481 } 482 implicitReceiverHierarchy.addAll(super.computeImplicitReceiversHierarchy()); 483 return implicitReceiverHierarchy; 484 } 485 486// @SuppressWarnings({"NullableProblems"}) 487 @NotNull 488 private Map<Name, PropertyDescriptor> getPropertyDescriptorsByFieldNames() { 489 if (propertyDescriptorsByFieldNames == null) { 490 propertyDescriptorsByFieldNames = new HashMap<Name, PropertyDescriptor>(); 491 } 492 return propertyDescriptorsByFieldNames; 493 } 494 495 @Override 496 public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) { 497 checkMayRead(); 498 499 if (!fieldName.asString().startsWith("$")) { 500 throw new IllegalStateException(); 501 } 502 503 PropertyDescriptor descriptor = getPropertyDescriptorsByFieldNames().get(fieldName); 504 if (descriptor != null) return descriptor; 505 return super.getPropertyByFieldReference(fieldName); 506 } 507 508 public List<VariableDescriptor> getDeclaredVariables() { 509 checkMayRead(); 510 511 List<VariableDescriptor> result = Lists.newArrayList(); 512 for (DeclarationDescriptor descriptor : getVariableClassOrNamespaceDescriptors().values()) { 513 if (descriptor instanceof VariableDescriptor) { 514 VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; 515 result.add(variableDescriptor); 516 } 517 } 518 return result; 519 } 520 521 public boolean hasDeclaredItems() { 522 return variableClassOrNamespaceDescriptors != null && !variableClassOrNamespaceDescriptors.isEmpty(); 523 } 524 525 private void addToDeclared(DeclarationDescriptor descriptor) { 526 declaredDescriptorsAccessibleBySimpleName.put(descriptor.getName(), descriptor); 527 } 528 529 @NotNull 530 @Override 531 public Multimap<Name, DeclarationDescriptor> getDeclaredDescriptorsAccessibleBySimpleName() { 532 return declaredDescriptorsAccessibleBySimpleName; 533 } 534 535 @NotNull 536 @Override 537 public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() { 538 return declaredDescriptorsAccessibleBySimpleName.values(); 539 } 540 541 private static boolean isObject(@NotNull ClassifierDescriptor classifier) { 542 if (classifier instanceof ClassDescriptor) { 543 ClassDescriptor clazz = (ClassDescriptor) classifier; 544 return clazz.getKind().isObject(); 545 } 546 else if (classifier instanceof TypeParameterDescriptor) { 547 return false; 548 } 549 else { 550 throw new IllegalStateException("unknown classifier: " + classifier); 551 } 552 } 553}