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 }