001 /* 002 * Copyright 2010-2016 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.js.translate.context; 018 019 import com.google.common.collect.Lists; 020 import com.google.common.collect.Maps; 021 import com.google.dart.compiler.backend.js.ast.*; 022 import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata; 023 import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties; 024 import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind; 025 import com.intellij.openapi.util.Factory; 026 import com.intellij.util.containers.ContainerUtil; 027 import com.intellij.util.containers.hash.LinkedHashMap; 028 import org.jetbrains.annotations.NotNull; 029 import org.jetbrains.annotations.Nullable; 030 import org.jetbrains.kotlin.builtins.ReflectionTypes; 031 import org.jetbrains.kotlin.descriptors.*; 032 import org.jetbrains.kotlin.js.config.JsConfig; 033 import org.jetbrains.kotlin.js.config.LibrarySourcesConfig; 034 import org.jetbrains.kotlin.js.translate.context.generator.Generator; 035 import org.jetbrains.kotlin.js.translate.context.generator.Rule; 036 import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics; 037 import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; 038 import org.jetbrains.kotlin.name.FqName; 039 import org.jetbrains.kotlin.resolve.BindingContext; 040 import org.jetbrains.kotlin.resolve.BindingTrace; 041 import org.jetbrains.kotlin.resolve.DescriptorUtils; 042 import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject; 043 044 import java.util.Collections; 045 import java.util.HashMap; 046 import java.util.List; 047 import java.util.Map; 048 049 import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*; 050 import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn; 051 import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.*; 052 import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledName; 053 import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName; 054 import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; 055 import static org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt.isDynamic; 056 057 /** 058 * Aggregates all the static parts of the context. 059 */ 060 public final class StaticContext { 061 062 public static StaticContext generateStaticContext(@NotNull BindingTrace bindingTrace, @NotNull JsConfig config, @NotNull ModuleDescriptor moduleDescriptor) { 063 JsProgram program = new JsProgram("main"); 064 Namer namer = Namer.newInstance(program.getRootScope()); 065 Intrinsics intrinsics = new Intrinsics(); 066 StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope()); 067 return new StaticContext(program, bindingTrace, namer, intrinsics, standardClasses, program.getRootScope(), config, moduleDescriptor); 068 } 069 070 @NotNull 071 private final JsProgram program; 072 073 @NotNull 074 private final BindingTrace bindingTrace; 075 @NotNull 076 private final Namer namer; 077 078 @NotNull 079 private final Intrinsics intrinsics; 080 081 @NotNull 082 private final StandardClasses standardClasses; 083 084 @NotNull 085 private final ReflectionTypes reflectionTypes; 086 087 @NotNull 088 private final JsScope rootScope; 089 090 @NotNull 091 private final Generator<JsName> names = new NameGenerator(); 092 @NotNull 093 private final Map<FqName, JsName> packageNames = Maps.newHashMap(); 094 @NotNull 095 private final Generator<JsScope> scopes = new ScopeGenerator(); 096 @NotNull 097 private final Generator<JsExpression> qualifiers = new QualifierGenerator(); 098 @NotNull 099 private final Generator<Boolean> qualifierIsNull = new QualifierIsNullGenerator(); 100 101 @NotNull 102 private final Map<JsScope, JsFunction> scopeToFunction = Maps.newHashMap(); 103 104 @NotNull 105 private final Map<MemberDescriptor, List<DeclarationDescriptor>> classOrConstructorClosure = Maps.newHashMap(); 106 107 @NotNull 108 private final Map<ClassDescriptor, List<DeferredCallSite>> deferredCallSites = new HashMap<ClassDescriptor, List<DeferredCallSite>>(); 109 110 @NotNull 111 private final JsConfig config; 112 113 @NotNull 114 private final Map<String, JsName> importedModules = new LinkedHashMap<String, JsName>(); 115 116 private Map<String, JsName> readOnlyImportedModules; 117 118 //TODO: too many parameters in constructor 119 private StaticContext( 120 @NotNull JsProgram program, 121 @NotNull BindingTrace bindingTrace, 122 @NotNull Namer namer, 123 @NotNull Intrinsics intrinsics, 124 @NotNull StandardClasses standardClasses, 125 @NotNull JsScope rootScope, 126 @NotNull JsConfig config, 127 @NotNull ModuleDescriptor moduleDescriptor 128 ) { 129 this.program = program; 130 this.bindingTrace = bindingTrace; 131 this.namer = namer; 132 this.intrinsics = intrinsics; 133 this.rootScope = rootScope; 134 this.standardClasses = standardClasses; 135 this.config = config; 136 this.reflectionTypes = new ReflectionTypes(moduleDescriptor); 137 } 138 139 @NotNull 140 public JsProgram getProgram() { 141 return program; 142 } 143 144 @NotNull 145 public BindingTrace getBindingTrace() { 146 return bindingTrace; 147 } 148 149 @NotNull 150 public BindingContext getBindingContext() { 151 return bindingTrace.getBindingContext(); 152 } 153 154 @NotNull 155 public Intrinsics getIntrinsics() { 156 return intrinsics; 157 } 158 159 @NotNull 160 public Namer getNamer() { 161 return namer; 162 } 163 164 @NotNull 165 public ReflectionTypes getReflectionTypes() { 166 return reflectionTypes; 167 } 168 169 @NotNull 170 private JsScope getRootScope() { 171 return rootScope; 172 } 173 174 @NotNull 175 public Map<String, JsName> getImportedModules() { 176 if (readOnlyImportedModules == null) { 177 readOnlyImportedModules = Collections.unmodifiableMap(importedModules); 178 } 179 return readOnlyImportedModules; 180 } 181 182 @NotNull 183 public JsScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) { 184 JsScope scope = scopes.get(descriptor.getOriginal()); 185 assert scope != null : "Must have a scope for descriptor"; 186 return scope; 187 } 188 189 @NotNull 190 public JsFunction getFunctionWithScope(@NotNull CallableDescriptor descriptor) { 191 JsScope scope = getScopeForDescriptor(descriptor); 192 JsFunction function = scopeToFunction.get(scope); 193 assert scope.equals(function.getScope()) : "Inconsistency."; 194 return function; 195 } 196 197 @NotNull 198 public JsNameRef getQualifiedReference(@NotNull DeclarationDescriptor descriptor) { 199 if (descriptor instanceof PackageViewDescriptor) { 200 return getQualifiedReference(((PackageViewDescriptor) descriptor).getFqName()); 201 } 202 if (descriptor instanceof PackageFragmentDescriptor) { 203 return getQualifiedReference(((PackageFragmentDescriptor) descriptor).getFqName()); 204 } 205 206 JsNameRef result = new JsNameRef(getNameForDescriptor(descriptor), getQualifierForDescriptor(descriptor)); 207 applySideEffects(result, descriptor); 208 return result; 209 } 210 211 @NotNull 212 public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) { 213 JsName packageName = getNameForPackage(packageFqName); 214 return pureFqn(packageName, packageFqName.isRoot() ? null : getQualifierForParentPackage(packageFqName.parent())); 215 } 216 217 @NotNull 218 public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) { 219 JsName name = names.get(descriptor.getOriginal()); 220 assert name != null : "Must have name for descriptor"; 221 return name; 222 } 223 224 @NotNull 225 public JsName getNameForPackage(@NotNull final FqName packageFqName) { 226 return ContainerUtil.getOrCreate(packageNames, packageFqName, new Factory<JsName>() { 227 @Override 228 public JsName create() { 229 String name = Namer.generatePackageName(packageFqName); 230 return getRootScope().declareName(name); 231 } 232 }); 233 } 234 235 @NotNull 236 private JsNameRef getQualifierForParentPackage(@NotNull FqName packageFqName) { 237 JsNameRef result = null; 238 JsNameRef qualifier = null; 239 240 FqName fqName = packageFqName; 241 242 while (true) { 243 JsNameRef ref = pureFqn(getNameForPackage(fqName), null); 244 245 if (qualifier == null) { 246 result = ref; 247 } 248 else { 249 qualifier.setQualifier(ref); 250 } 251 252 qualifier = ref; 253 254 if (fqName.isRoot()) break; 255 fqName = fqName.parent(); 256 } 257 258 return result; 259 } 260 261 @NotNull 262 public JsConfig getConfig() { 263 return config; 264 } 265 266 private final class NameGenerator extends Generator<JsName> { 267 268 public NameGenerator() { 269 Rule<JsName> namesForDynamic = new Rule<JsName>() { 270 @Override 271 @Nullable 272 public JsName apply(@NotNull DeclarationDescriptor descriptor) { 273 if (isDynamic(descriptor)) { 274 String name = descriptor.getName().asString(); 275 return JsDynamicScope.INSTANCE.declareName(name); 276 } 277 278 return null; 279 } 280 }; 281 282 Rule<JsName> localClasses = new Rule<JsName>() { 283 @Nullable 284 @Override 285 public JsName apply(@NotNull DeclarationDescriptor descriptor) { 286 if (!DescriptorUtils.isDescriptorWithLocalVisibility(descriptor) || 287 !DescriptorUtils.isClass(descriptor)) { 288 return null; 289 } 290 291 String suggested = getSuggestedName(descriptor); 292 293 descriptor = getParentOfType(descriptor, ClassOrPackageFragmentDescriptor.class, true); 294 assert descriptor != null; 295 296 JsScope scope = getScopeForDescriptor(descriptor); 297 return scope.declareFreshName(suggested); 298 } 299 }; 300 301 Rule<JsName> namesForStandardClasses = new Rule<JsName>() { 302 @Override 303 @Nullable 304 public JsName apply(@NotNull DeclarationDescriptor data) { 305 if (!standardClasses.isStandardObject(data)) { 306 return null; 307 } 308 return standardClasses.getStandardObjectName(data); 309 } 310 }; 311 Rule<JsName> memberDeclarationsInsideParentsScope = new Rule<JsName>() { 312 @Override 313 @Nullable 314 public JsName apply(@NotNull DeclarationDescriptor descriptor) { 315 JsScope scope = getEnclosingScope(descriptor); 316 return scope.declareFreshName(getSuggestedName(descriptor)); 317 } 318 }; 319 Rule<JsName> constructorOrNativeCompanionObjectHasTheSameNameAsTheClass = new Rule<JsName>() { 320 @Override 321 public JsName apply(@NotNull DeclarationDescriptor descriptor) { 322 if (descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary() || 323 DescriptorUtils.isCompanionObject(descriptor) && isNativeObject(descriptor)) { 324 //noinspection ConstantConditions 325 return getNameForDescriptor(descriptor.getContainingDeclaration()); 326 } 327 return null; 328 } 329 }; 330 331 // ecma 5 property name never declares as obfuscatable: 332 // 1) property cannot be overloaded, so, name collision is not possible 333 // 2) main reason: if property doesn't have any custom accessor, value holder will have the same name as accessor, so, the same name will be declared more than once 334 // 335 // But extension property may obfuscatable, because transform into function. Example: String.foo = 1, Int.foo = 2 336 Rule<JsName> propertyOrPropertyAccessor = new Rule<JsName>() { 337 @Override 338 public JsName apply(@NotNull DeclarationDescriptor descriptor) { 339 PropertyDescriptor propertyDescriptor; 340 if (descriptor instanceof PropertyAccessorDescriptor) { 341 propertyDescriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty(); 342 } 343 else if (descriptor instanceof PropertyDescriptor) { 344 propertyDescriptor = (PropertyDescriptor) descriptor; 345 } 346 else { 347 return null; 348 } 349 350 String nameFromAnnotation = getNameForAnnotatedObjectWithOverrides(propertyDescriptor); 351 if (nameFromAnnotation != null) { 352 return declarePropertyOrPropertyAccessorName(descriptor, nameFromAnnotation, false); 353 } 354 355 String propertyName = getSuggestedName(propertyDescriptor); 356 357 if (!isExtension(propertyDescriptor)) { 358 if (Visibilities.isPrivate(propertyDescriptor.getVisibility())) { 359 propertyName = getMangledName(propertyDescriptor, propertyName); 360 } 361 return declarePropertyOrPropertyAccessorName(descriptor, propertyName, false); 362 } else { 363 assert !(descriptor instanceof PropertyDescriptor) : "descriptor should not be instance of PropertyDescriptor: " + descriptor; 364 365 boolean isGetter = descriptor instanceof PropertyGetterDescriptor; 366 String accessorName = Namer.getNameForAccessor(propertyName, isGetter, false); 367 return declarePropertyOrPropertyAccessorName(descriptor, accessorName, false); 368 } 369 } 370 }; 371 372 Rule<JsName> predefinedObjectsHasUnobfuscatableNames = new Rule<JsName>() { 373 @Override 374 public JsName apply(@NotNull DeclarationDescriptor descriptor) { 375 // The mixing of override and rename by annotation(e.g. native) is forbidden. 376 if (descriptor instanceof CallableMemberDescriptor && 377 !((CallableMemberDescriptor) descriptor).getOverriddenDescriptors().isEmpty()) { 378 return null; 379 } 380 381 if (descriptor instanceof ConstructorDescriptor) { 382 DeclarationDescriptor classDescriptor = descriptor.getContainingDeclaration(); 383 assert classDescriptor != null; 384 descriptor = classDescriptor; 385 } 386 387 String name = getNameForAnnotatedObjectWithOverrides(descriptor); 388 if (name != null) return getEnclosingScope(descriptor).declareName(name); 389 return null; 390 } 391 }; 392 393 Rule<JsName> overridingDescriptorsReferToOriginalName = new Rule<JsName>() { 394 @Override 395 public JsName apply(@NotNull DeclarationDescriptor descriptor) { 396 //TODO: refactor 397 if (!(descriptor instanceof FunctionDescriptor)) { 398 return null; 399 } 400 FunctionDescriptor overriddenDescriptor = getOverriddenDescriptor((FunctionDescriptor) descriptor); 401 if (overriddenDescriptor == null) { 402 return null; 403 } 404 405 JsScope scope = getEnclosingScope(descriptor); 406 JsName result = getNameForDescriptor(overriddenDescriptor); 407 scope.declareName(result.getIdent()); 408 return result; 409 } 410 }; 411 412 Rule<JsName> fakeCallableDescriptor = new Rule<JsName>() { 413 @Nullable 414 @Override 415 public JsName apply(@NotNull DeclarationDescriptor descriptor) { 416 if (!(descriptor instanceof FakeCallableDescriptorForObject)) { 417 return null; 418 } 419 420 FakeCallableDescriptorForObject fakeCallableDescriptor = (FakeCallableDescriptorForObject) descriptor; 421 return getNameForDescriptor(fakeCallableDescriptor.getReferencedDescriptor()); 422 } 423 }; 424 425 addRule(namesForDynamic); 426 addRule(localClasses); 427 addRule(namesForStandardClasses); 428 addRule(constructorOrNativeCompanionObjectHasTheSameNameAsTheClass); 429 addRule(propertyOrPropertyAccessor); 430 addRule(predefinedObjectsHasUnobfuscatableNames); 431 addRule(overridingDescriptorsReferToOriginalName); 432 addRule(fakeCallableDescriptor); 433 addRule(memberDeclarationsInsideParentsScope); 434 } 435 } 436 437 @NotNull 438 public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name, boolean fresh) { 439 JsScope scope = getEnclosingScope(descriptor); 440 return fresh ? scope.declareFreshName(name) : scope.declareName(name); 441 } 442 443 @NotNull 444 private JsScope getEnclosingScope(@NotNull DeclarationDescriptor descriptor) { 445 DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor); 446 return getScopeForDescriptor(containingDeclaration.getOriginal()); 447 } 448 449 private final class ScopeGenerator extends Generator<JsScope> { 450 451 public ScopeGenerator() { 452 Rule<JsScope> generateNewScopesForClassesWithNoAncestors = new Rule<JsScope>() { 453 @Override 454 public JsScope apply(@NotNull DeclarationDescriptor descriptor) { 455 if (!(descriptor instanceof ClassDescriptor)) { 456 return null; 457 } 458 if (getSuperclass((ClassDescriptor) descriptor) == null) { 459 return getRootScope().innerObjectScope("Scope for class " + descriptor.getName()); 460 } 461 return null; 462 } 463 }; 464 Rule<JsScope> generateInnerScopesForDerivedClasses = new Rule<JsScope>() { 465 @Override 466 public JsScope apply(@NotNull DeclarationDescriptor descriptor) { 467 if (!(descriptor instanceof ClassDescriptor)) { 468 return null; 469 } 470 ClassDescriptor superclass = getSuperclass((ClassDescriptor) descriptor); 471 if (superclass == null) { 472 return null; 473 } 474 return getScopeForDescriptor(superclass).innerObjectScope("Scope for class " + descriptor.getName()); 475 } 476 }; 477 Rule<JsScope> generateNewScopesForPackageDescriptors = new Rule<JsScope>() { 478 @Override 479 public JsScope apply(@NotNull DeclarationDescriptor descriptor) { 480 if (!(descriptor instanceof PackageFragmentDescriptor)) { 481 return null; 482 } 483 return getRootScope().innerObjectScope("Package " + descriptor.getName()); 484 } 485 }; 486 //TODO: never get there 487 Rule<JsScope> generateInnerScopesForMembers = new Rule<JsScope>() { 488 @Override 489 public JsScope apply(@NotNull DeclarationDescriptor descriptor) { 490 JsScope enclosingScope = getEnclosingScope(descriptor); 491 return enclosingScope.innerObjectScope("Scope for member " + descriptor.getName()); 492 } 493 }; 494 Rule<JsScope> createFunctionObjectsForCallableDescriptors = new Rule<JsScope>() { 495 @Override 496 public JsScope apply(@NotNull DeclarationDescriptor descriptor) { 497 if (!(descriptor instanceof CallableDescriptor)) { 498 return null; 499 } 500 JsScope enclosingScope = getEnclosingScope(descriptor); 501 502 JsFunction correspondingFunction = JsAstUtils.createFunctionWithEmptyBody(enclosingScope); 503 assert (!scopeToFunction.containsKey(correspondingFunction.getScope())) : "Scope to function value overridden for " + descriptor; 504 scopeToFunction.put(correspondingFunction.getScope(), correspondingFunction); 505 return correspondingFunction.getScope(); 506 } 507 }; 508 addRule(createFunctionObjectsForCallableDescriptors); 509 addRule(generateNewScopesForClassesWithNoAncestors); 510 addRule(generateInnerScopesForDerivedClasses); 511 addRule(generateNewScopesForPackageDescriptors); 512 addRule(generateInnerScopesForMembers); 513 } 514 } 515 516 @Nullable 517 public JsExpression getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) { 518 if (qualifierIsNull.get(descriptor.getOriginal()) != null) { 519 return null; 520 } 521 return qualifiers.get(descriptor.getOriginal()); 522 } 523 524 private final class QualifierGenerator extends Generator<JsExpression> { 525 public QualifierGenerator() { 526 Rule<JsExpression> standardObjectsHaveKotlinQualifier = new Rule<JsExpression>() { 527 @Override 528 public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 529 if (!standardClasses.isStandardObject(descriptor)) { 530 return null; 531 } 532 return Namer.kotlinObject(); 533 } 534 }; 535 //TODO: review and refactor 536 Rule<JsExpression> packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier = new Rule<JsExpression>() { 537 @Override 538 public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 539 if (isNativeObject(descriptor)) return null; 540 541 DeclarationDescriptor containingDescriptor = getContainingDeclaration(descriptor); 542 if (!(containingDescriptor instanceof PackageFragmentDescriptor)) { 543 return null; 544 } 545 546 JsNameRef result = getQualifierForParentPackage(((PackageFragmentDescriptor) containingDescriptor).getFqName()); 547 548 JsExpression moduleExpression = getModuleExpressionFor(descriptor); 549 return moduleExpression != null ? JsAstUtils.replaceRootReference(result, moduleExpression) : result; 550 } 551 }; 552 Rule<JsExpression> constructorOrCompanionObjectHasTheSameQualifierAsTheClass = new Rule<JsExpression>() { 553 @Override 554 public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 555 if (descriptor instanceof ConstructorDescriptor || 556 isNativeObject(descriptor) && DescriptorUtils.isCompanionObject(descriptor)) { 557 //noinspection ConstantConditions 558 return getQualifierForDescriptor(descriptor.getContainingDeclaration()); 559 } 560 return null; 561 } 562 }; 563 Rule<JsExpression> libraryObjectsHaveKotlinQualifier = new Rule<JsExpression>() { 564 @Override 565 public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 566 if (isLibraryObject(descriptor)) { 567 return Namer.kotlinObject(); 568 } 569 return null; 570 } 571 }; 572 Rule<JsExpression> nativeObjectsHaveNativePartOfFullQualifier = new Rule<JsExpression>() { 573 @Override 574 public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 575 if (descriptor instanceof ConstructorDescriptor || !isNativeObject(descriptor)) return null; 576 577 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 578 if (containingDeclaration != null && isNativeObject(containingDeclaration)) { 579 return isCompanionObject(descriptor) ? getQualifierForDescriptor(containingDeclaration) : 580 getQualifiedReference(containingDeclaration); 581 } 582 583 return null; 584 } 585 }; 586 Rule<JsExpression> staticMembersHaveContainerQualifier = new Rule<JsExpression>() { 587 @Override 588 public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 589 if (descriptor instanceof CallableDescriptor && !isNativeObject(descriptor)) { 590 CallableDescriptor callableDescriptor = (CallableDescriptor) descriptor; 591 if (DescriptorUtils.isStaticDeclaration(callableDescriptor)) { 592 return getQualifiedReference(callableDescriptor.getContainingDeclaration()); 593 } 594 } 595 596 return null; 597 } 598 }; 599 Rule<JsExpression> nestedClassesHaveContainerQualifier = new Rule<JsExpression>() { 600 @Nullable 601 @Override 602 public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 603 if (!(descriptor instanceof ClassDescriptor)) { 604 return null; 605 } 606 DeclarationDescriptor container = getParentOfType(descriptor, ClassDescriptor.class); 607 if (container == null) { 608 return null; 609 } 610 611 if (isNativeObject(descriptor)) { 612 return null; 613 } 614 return getQualifiedReference(container); 615 } 616 }; 617 618 Rule<JsExpression> localClassesHavePackageQualifier = new Rule<JsExpression>() { 619 @Nullable 620 @Override 621 public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 622 if (!DescriptorUtils.isDescriptorWithLocalVisibility(descriptor) || !(descriptor instanceof ClassDescriptor)) { 623 return null; 624 } 625 626 descriptor = getParentOfType(descriptor, PackageFragmentDescriptor.class, true); 627 assert descriptor != null; 628 return getQualifiedReference(descriptor); 629 } 630 }; 631 632 addRule(libraryObjectsHaveKotlinQualifier); 633 addRule(constructorOrCompanionObjectHasTheSameQualifierAsTheClass); 634 addRule(standardObjectsHaveKotlinQualifier); 635 addRule(packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier); 636 addRule(nativeObjectsHaveNativePartOfFullQualifier); 637 addRule(staticMembersHaveContainerQualifier); 638 addRule(nestedClassesHaveContainerQualifier); 639 addRule(localClassesHavePackageQualifier); 640 } 641 } 642 643 @Nullable 644 public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) { 645 String moduleName = getExternalModuleName(descriptor); 646 if (moduleName == null) return null; 647 648 if (LibrarySourcesConfig.UNKNOWN_EXTERNAL_MODULE_NAME.equals(moduleName)) return null; 649 650 JsName moduleId = moduleName.equals(Namer.KOTLIN_LOWER_NAME) ? rootScope.declareName(Namer.KOTLIN_NAME) : 651 importedModules.get(moduleName); 652 if (moduleId == null) { 653 moduleId = rootScope.declareFreshName(Namer.LOCAL_MODULE_PREFIX + Namer.suggestedModuleName(moduleName)); 654 importedModules.put(moduleName, moduleId); 655 } 656 657 return JsAstUtils.pureFqn(moduleId, null); 658 } 659 660 private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) { 661 if (expression instanceof HasMetadata) { 662 if (descriptor instanceof FunctionDescriptor || 663 descriptor instanceof PackageFragmentDescriptor || 664 descriptor instanceof ClassDescriptor 665 ) { 666 MetadataProperties.setSideEffects((HasMetadata) expression, SideEffectKind.PURE); 667 } 668 } 669 return expression; 670 } 671 672 private static class QualifierIsNullGenerator extends Generator<Boolean> { 673 674 private QualifierIsNullGenerator() { 675 Rule<Boolean> propertiesInClassHaveNoQualifiers = new Rule<Boolean>() { 676 @Override 677 public Boolean apply(@NotNull DeclarationDescriptor descriptor) { 678 if ((descriptor instanceof PropertyDescriptor) && descriptor.getContainingDeclaration() instanceof ClassDescriptor) { 679 return true; 680 } 681 return null; 682 } 683 }; 684 addRule(propertiesInClassHaveNoQualifiers); 685 } 686 } 687 688 public void putClassOrConstructorClosure(@NotNull MemberDescriptor localClass, @NotNull List<DeclarationDescriptor> closure) { 689 classOrConstructorClosure.put(localClass, Lists.newArrayList(closure)); 690 } 691 692 @Nullable 693 public List<DeclarationDescriptor> getClassOrConstructorClosure(@NotNull MemberDescriptor descriptor) { 694 List<DeclarationDescriptor> result = classOrConstructorClosure.get(descriptor); 695 return result != null ? Lists.newArrayList(result) : null; 696 } 697 698 @NotNull 699 public Map<ClassDescriptor, List<DeferredCallSite>> getDeferredCallSites() { 700 return deferredCallSites; 701 } 702 }