FqNameUnsafe

This commit is contained in:
Stepan Koltsov
2012-03-15 19:28:29 +04:00
parent 4c12f61a28
commit 1610c9b3a0
13 changed files with 317 additions and 142 deletions
@@ -113,7 +113,7 @@ public abstract class CodegenContext {
while(!(descriptor instanceof NamespaceDescriptor)) {
descriptor = descriptor.getContainingDeclaration();
}
return NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(descriptor), true);
return NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(descriptor).toSafe(), true);
}
public OwnerKind getContextKind() {
@@ -318,7 +318,7 @@ public class FunctionCodegen {
int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
String ownerInternalName = contextClass instanceof NamespaceDescriptor ?
NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(contextClass), true) :
NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(contextClass).toSafe(), true) :
state.getTypeMapper().mapType(((ClassDescriptor) contextClass).getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName();
String descriptor = jvmSignature.getDescriptor().replace(")","I)");
@@ -114,9 +114,9 @@ public class JetTypeMapper {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof JavaNamespaceDescriptor) {
JavaNamespaceDescriptor javaNamespaceDescriptor = (JavaNamespaceDescriptor) containingDeclaration;
owner = NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(containingDeclaration), javaNamespaceDescriptor.isNamespace());
owner = NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(containingDeclaration).toSafe(), javaNamespaceDescriptor.isNamespace());
} else if (containingDeclaration instanceof NamespaceDescriptor) {
owner = NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(containingDeclaration), true);
owner = NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(containingDeclaration).toSafe(), true);
}
else if (containingDeclaration instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
@@ -395,7 +395,7 @@ public class JetTypeMapper {
if (functionParent instanceof JavaNamespaceDescriptor) {
namespace = ((JavaNamespaceDescriptor) functionParent).isNamespace();
}
owner = NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(functionParent), namespace);
owner = NamespaceCodegen.getJVMClassName(DescriptorUtils.getFQName(functionParent).toSafe(), namespace);
ownerForDefaultImpl = ownerForDefaultParam = owner;
invokeOpcode = INVOKESTATIC;
thisClass = null;
@@ -66,7 +66,7 @@ public class JavaBridgeConfiguration implements ModuleConfiguration {
@Override
public void extendNamespaceScope(@NotNull BindingTrace trace, @NotNull NamespaceDescriptor namespaceDescriptor, @NotNull WritableScope namespaceMemberScope) {
namespaceMemberScope.importScope(new JavaPackageScope(DescriptorUtils.getFQName(namespaceDescriptor), namespaceDescriptor, javaSemanticServices));
namespaceMemberScope.importScope(new JavaPackageScope(DescriptorUtils.getFQName(namespaceDescriptor).toSafe(), namespaceDescriptor, javaSemanticServices));
delegateConfiguration.extendNamespaceScope(trace, namespaceDescriptor, namespaceMemberScope);
}
@@ -178,25 +178,28 @@ public class DescriptorUtils {
return false;
}
public static FqName getFQName(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof ModuleDescriptor || descriptor.getContainingDeclaration() instanceof ModuleDescriptor) {
return FqName.ROOT;
@NotNull
public static FqNameUnsafe getFQName(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (descriptor instanceof ModuleDescriptor || containingDeclaration instanceof ModuleDescriptor) {
return FqName.ROOT.toUnsafe();
}
if (descriptor.getContainingDeclaration() == null) {
if (containingDeclaration == null) {
if (descriptor instanceof NamespaceDescriptor) {
// TODO: namespace must always have parent
if (descriptor.getName().equals("jet")) {
return FqName.topLevel("jet");
return FqNameUnsafe.topLevel("jet");
}
if (descriptor.getName().equals("<java_root>")) {
return FqName.ROOT;
return FqName.ROOT.toUnsafe();
}
}
throw new IllegalStateException("descriptor is not module descriptor and has null containingDeclaration: " + descriptor.getContainingDeclaration());
throw new IllegalStateException("descriptor is not module descriptor and has null containingDeclaration: " + containingDeclaration);
}
return getFQName(descriptor.getContainingDeclaration()).child(descriptor.getName());
return getFQName(containingDeclaration).child(descriptor.getName());
}
public static boolean isTopLevelFunction(@NotNull SimpleFunctionDescriptor functionDescriptor) {
@@ -18,9 +18,7 @@ package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
@@ -31,60 +29,50 @@ public class FqName {
public static final FqName ROOT = new FqName("");
@NotNull
private final String fqName;
private final FqNameUnsafe fqName;
// cache
private transient FqName parent;
private transient String shortName;
public FqName(@NotNull String fqName) {
this.fqName = new FqNameUnsafe(fqName, this);
}
public FqName(@NotNull FqNameUnsafe fqName) {
this.fqName = fqName;
validateFqName();
}
private FqName(@NotNull String fqName, FqName parent, String shortName) {
private FqName(@NotNull FqNameUnsafe fqName, FqName parent) {
this.fqName = fqName;
this.parent = parent;
this.shortName = shortName;
validateFqName();
}
private void validateFqName() {
if (fqName.length() == 0) {
return;
}
// TODO: prohibit < everywhere
if (fqName.indexOf('/') >= 0 || fqName.charAt(0) == '<') {
if (fqName.getFqName().indexOf('<') >= 0) {
throw new IllegalArgumentException("incorrect fq name: " + fqName);
}
}
private void compute() {
int lastDot = fqName.lastIndexOf('.');
if (lastDot >= 0) {
shortName = fqName.substring(lastDot + 1);
parent = new FqName(fqName.substring(0, lastDot));
} else {
shortName = fqName;
parent = ROOT;
}
}
@NotNull
public String getFqName() {
return fqName.getFqName();
}
@NotNull
public FqNameUnsafe toUnsafe() {
return fqName;
}
public boolean isRoot() {
return fqName.equals("");
return fqName.isRoot();
}
@NotNull
public FqName parent() {
if (parent != null) {
@@ -95,49 +83,30 @@ public class FqName {
throw new IllegalStateException("root");
}
compute();
parent = new FqName(fqName.parent());
return parent;
}
@NotNull
public FqName child(@NotNull String name) {
String childFqName;
if (isRoot()) {
childFqName = name;
} else {
childFqName = fqName + "." + name;
}
return new FqName(childFqName, this, name);
return new FqName(fqName.child(name), this);
}
@NotNull
public String shortName() {
if (shortName != null) {
return shortName;
}
if (isRoot()) {
throw new IllegalStateException("root");
}
compute();
return shortName;
}
private interface WalkCallback {
void segment(@NotNull String shortName, @NotNull FqName fqName);
return fqName.shortName();
}
@NotNull
public List<FqName> path() {
final List<FqName> path = Lists.newArrayList();
path.add(ROOT);
walk(new WalkCallback() {
fqName.walk(new FqNameUnsafe.WalkCallback() {
@Override
public void segment(@NotNull String shortName, @NotNull FqName fqName) {
path.add(fqName);
public void segment(@NotNull String shortName, @NotNull FqNameUnsafe fqName) {
// TODO: do not validate
path.add(new FqName(fqName));
}
});
return path;
@@ -145,75 +114,19 @@ public class FqName {
@NotNull
public List<String> pathSegments() {
final List<String> path = Lists.newArrayList();
walk(new WalkCallback() {
@Override
public void segment(@NotNull String shortName, @NotNull FqName fqName) {
path.add(shortName);
}
});
return path;
return fqName.pathSegments();
}
private void walk(@NotNull WalkCallback callback) {
if (isRoot()) {
return;
}
int pos = fqName.indexOf('.');
if (pos < 0) {
if (this.parent == null) {
this.parent = ROOT;
}
if (this.shortName == null) {
this.shortName = fqName;
}
callback.segment(fqName, this);
return;
}
String firstSegment = fqName.substring(0, pos);
FqName last = new FqName(firstSegment, ROOT, firstSegment);
callback.segment(firstSegment, last);
for (;;) {
int next = fqName.indexOf('.', pos + 1);
if (next < 0) {
if (this.parent == null) {
this.parent = last;
}
String shortName = fqName.substring(pos + 1);
if (this.shortName == null) {
this.shortName = shortName;
}
callback.segment(shortName, this);
return;
}
String shortName = fqName.substring(pos + 1, next);
last = new FqName(fqName.substring(0, next), last, shortName);
callback.segment(shortName, last);
pos = next;
}
}
@NotNull
public static FqName topLevel(@NotNull String shortName) {
if (shortName.indexOf('.') >= 0) {
throw new IllegalArgumentException();
}
return new FqName(shortName, ROOT, shortName);
return new FqName(FqNameUnsafe.topLevel(shortName));
}
@Override
public String toString() {
return isRoot() ? "<root>" : fqName;
return fqName.toString();
}
@Override
@@ -0,0 +1,247 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Like {@link FqName} but allows '<' and '>' characters in name.
*
* @author Stepan Koltsov
*/
public class FqNameUnsafe {
@NotNull
private final String fqName;
// cache
private transient FqName safe;
private transient FqNameUnsafe parent;
private transient String shortName;
FqNameUnsafe(@NotNull String fqName, @NotNull FqName safe) {
this.fqName = fqName;
this.safe = safe;
validateFqName();
}
public FqNameUnsafe(@NotNull String fqName) {
this.fqName = fqName;
validateFqName();
}
private FqNameUnsafe(@NotNull String fqName, FqNameUnsafe parent, String shortName) {
this.fqName = fqName;
this.parent = parent;
this.shortName = shortName;
validateFqName();
}
private void validateFqName() {
if (fqName.indexOf('/') >= 0) {
throw new IllegalArgumentException("incorrect fq name: " + fqName);
}
}
private void compute() {
int lastDot = fqName.lastIndexOf('.');
if (lastDot >= 0) {
shortName = fqName.substring(lastDot + 1);
parent = new FqNameUnsafe(fqName.substring(0, lastDot));
} else {
shortName = fqName;
parent = FqName.ROOT.toUnsafe();
}
}
@NotNull
public String getFqName() {
return fqName;
}
@NotNull
public FqName toSafe() {
if (safe != null) {
return safe;
}
safe = new FqName(this);
return safe;
}
public boolean isRoot() {
return fqName.equals("");
}
@NotNull
public FqNameUnsafe parent() {
if (parent != null) {
return parent;
}
if (isRoot()) {
throw new IllegalStateException("root");
}
compute();
return parent;
}
@NotNull
public FqNameUnsafe child(@NotNull String name) {
String childFqName;
if (isRoot()) {
childFqName = name;
} else {
childFqName = fqName + "." + name;
}
return new FqNameUnsafe(childFqName, this, name);
}
@NotNull
public String shortName() {
if (shortName != null) {
return shortName;
}
if (isRoot()) {
throw new IllegalStateException("root");
}
compute();
return shortName;
}
interface WalkCallback {
void segment(@NotNull String shortName, @NotNull FqNameUnsafe fqName);
}
@NotNull
public List<FqNameUnsafe> path() {
final List<FqNameUnsafe> path = Lists.newArrayList();
path.add(FqName.ROOT.toUnsafe());
walk(new WalkCallback() {
@Override
public void segment(@NotNull String shortName, @NotNull FqNameUnsafe fqName) {
path.add(fqName);
}
});
return path;
}
@NotNull
public List<String> pathSegments() {
final List<String> path = Lists.newArrayList();
walk(new WalkCallback() {
@Override
public void segment(@NotNull String shortName, @NotNull FqNameUnsafe fqName) {
path.add(shortName);
}
});
return path;
}
void walk(@NotNull WalkCallback callback) {
if (isRoot()) {
return;
}
int pos = fqName.indexOf('.');
if (pos < 0) {
if (this.parent == null) {
this.parent = FqName.ROOT.toUnsafe();
}
if (this.shortName == null) {
this.shortName = fqName;
}
callback.segment(fqName, this);
return;
}
String firstSegment = fqName.substring(0, pos);
FqNameUnsafe last = new FqNameUnsafe(firstSegment, FqName.ROOT.toUnsafe(), firstSegment);
callback.segment(firstSegment, last);
for (;;) {
int next = fqName.indexOf('.', pos + 1);
if (next < 0) {
if (this.parent == null) {
this.parent = last;
}
String shortName = fqName.substring(pos + 1);
if (this.shortName == null) {
this.shortName = shortName;
}
callback.segment(shortName, this);
return;
}
String shortName = fqName.substring(pos + 1, next);
last = new FqNameUnsafe(fqName.substring(0, next), last, shortName);
callback.segment(shortName, last);
pos = next;
}
}
@NotNull
public static FqNameUnsafe topLevel(@NotNull String shortName) {
if (shortName.indexOf('.') >= 0) {
throw new IllegalArgumentException();
}
return new FqNameUnsafe(shortName, FqName.ROOT.toUnsafe(), shortName);
}
@Override
public String toString() {
return isRoot() ? "<root>" : fqName;
}
@Override
public boolean equals(Object o) {
// generated by Idea
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FqNameUnsafe that = (FqNameUnsafe) o;
if (fqName != null ? !fqName.equals(that.fqName) : that.fqName != null) return false;
return true;
}
@Override
public int hashCode() {
// generated by Idea
return fqName != null ? fqName.hashCode() : 0;
}
}
@@ -119,7 +119,7 @@ public class NamespaceFactoryImpl implements NamespaceFactory {
namespaceDescriptor = ((ModuleDescriptor) owner).getRootNs();
}
else {
FqName ownerFqName = DescriptorUtils.getFQName(owner);
FqName ownerFqName = DescriptorUtils.getFQName(owner).toSafe();
fqName = ownerFqName.child(name);
namespaceDescriptor = ((NamespaceDescriptorImpl) owner).getNamespace(name);
}
@@ -18,6 +18,7 @@ package org.jetbrains.jet;
import com.google.common.collect.Lists;
import org.jetbrains.jet.lang.resolve.FqName;
import org.jetbrains.jet.lang.resolve.FqNameUnsafe;
import org.junit.Assert;
import org.junit.Test;
@@ -85,4 +86,15 @@ public class FqNameTest {
}
}
@Test
public void safeUnsafe() {
FqName fqName = new FqName("com.yandex");
Assert.assertSame(fqName, fqName.toUnsafe().toSafe());
}
@Test
public void unsafeSafe() {
FqNameUnsafe fqName = new FqNameUnsafe("ru.yandex");
Assert.assertSame(fqName, fqName.toSafe().toUnsafe());
}
}
@@ -40,7 +40,7 @@ public class JetPluginUtil {
@NotNull
public static FqName computeTypeFullName(@NotNull JetType type) {
ClassDescriptor clazz = (ClassDescriptor) type.getConstructor().getDeclarationDescriptor();
return DescriptorUtils.getFQName(clazz);
return DescriptorUtils.getFQName(clazz).toSafe();
}
@NotNull
@@ -134,7 +134,7 @@ public class JetFunctionInsertHandler implements InsertHandler<LookupElement> {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
final FqName fqn = DescriptorUtils.getFQName(functionDescriptor);
final FqName fqn = DescriptorUtils.getFQName(functionDescriptor).toSafe();
ImportClassHelper.addImportDirective(fqn.getFqName(), file);
}
});
@@ -101,7 +101,7 @@ public class ImportClassAndFunFix extends JetHintAction<JetSimpleNameExpression>
@Override
public FqName apply(@Nullable DeclarationDescriptor declarationDescriptor) {
assert declarationDescriptor != null;
return DescriptorUtils.getFQName(declarationDescriptor);
return DescriptorUtils.getFQName(declarationDescriptor).toSafe();
}
});
}
@@ -126,7 +126,7 @@ public class ImportClassAndFunFix extends JetHintAction<JetSimpleNameExpression>
@Override
public FqName apply(@Nullable DeclarationDescriptor declarationDescriptor) {
assert declarationDescriptor != null;
return DescriptorUtils.getFQName(declarationDescriptor);
return DescriptorUtils.getFQName(declarationDescriptor).toSafe();
}
});
}
@@ -22,7 +22,7 @@ import com.google.dart.compiler.backend.js.ast.JsScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.resolve.FqName;
import org.jetbrains.jet.lang.resolve.FqNameUnsafe;
import java.util.Map;
@@ -39,13 +39,13 @@ public final class StandardClasses {
private final class Builder {
@Nullable
private /*var*/ FqName currentFQName = null;
private /*var*/ FqNameUnsafe currentFQName = null;
@Nullable
private /*var*/ String currentObjectName = null;
@NotNull
public Builder forFQ(@NotNull String classFQName) {
currentFQName = new FqName(classFQName);
currentFQName = new FqNameUnsafe(classFQName);
return this;
}
@@ -119,46 +119,46 @@ public final class StandardClasses {
@NotNull
private final Map<FqName, JsName> standardObjects = Maps.newHashMap();
private final Map<FqNameUnsafe, JsName> standardObjects = Maps.newHashMap();
@NotNull
private final Map<FqName, JsScope> scopeMap = Maps.newHashMap();
private final Map<FqNameUnsafe, JsScope> scopeMap = Maps.newHashMap();
private StandardClasses(@NotNull JsScope kotlinScope) {
this.kotlinScope = kotlinScope;
}
private void declareTopLevelObjectInScope(@NotNull JsScope scope, @NotNull Map<FqName, JsName> map,
@NotNull FqName fullQualifiedName, @NotNull String name) {
private void declareTopLevelObjectInScope(@NotNull JsScope scope, @NotNull Map<FqNameUnsafe, JsName> map,
@NotNull FqNameUnsafe fullQualifiedName, @NotNull String name) {
JsName declaredName = scope.declareName(name);
declaredName.setObfuscatable(false);
map.put(fullQualifiedName, declaredName);
scopeMap.put(fullQualifiedName, new JsScope(scope, "scope for " + name));
}
private void declareKotlinObject(@NotNull FqName fullQualifiedName, @NotNull String kotlinLibName) {
private void declareKotlinObject(@NotNull FqNameUnsafe fullQualifiedName, @NotNull String kotlinLibName) {
declareTopLevelObjectInScope(kotlinScope, standardObjects, fullQualifiedName, kotlinLibName);
}
private void declareInner(@NotNull FqName fullQualifiedClassName,
private void declareInner(@NotNull FqNameUnsafe fullQualifiedClassName,
@NotNull String shortMethodName,
@NotNull String javascriptName) {
JsScope classScope = scopeMap.get(fullQualifiedClassName);
assert classScope != null;
FqName fullQualifiedMethodName = new FqName(fullQualifiedClassName + "." + shortMethodName);
FqNameUnsafe fullQualifiedMethodName = fullQualifiedClassName.child(shortMethodName);
JsName declaredName = classScope.declareName(javascriptName);
declaredName.setObfuscatable(false);
standardObjects.put(fullQualifiedMethodName, declaredName);
}
private void declareMethods(@NotNull FqName classFQName,
private void declareMethods(@NotNull FqNameUnsafe classFQName,
@NotNull String... methodNames) {
for (String methodName : methodNames) {
declareInner(classFQName, methodName, methodName);
}
}
private void declareReadonlyProperties(@NotNull FqName classFQName,
private void declareReadonlyProperties(@NotNull FqNameUnsafe classFQName,
@NotNull String... propertyNames) {
for (String propertyName : propertyNames) {
declareInner(classFQName, propertyName, propertyName);