提交 4c8cd6ca 编写于 作者: S Stepan Koltsov

NamespaceFactory

* extract NamespaceFactory from TypeHierarchyResolver
* implement NamespaceFactory.createNamespaceDescriptorPathIfNeeded(FqName)
* FqName .path() and .pathSegments() utilities
上级 e1afdbff
......@@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.TypeResolver;
import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver;
import org.jetbrains.jet.lang.resolve.ImportsResolver;
import org.jetbrains.jet.lang.resolve.DelegationResolver;
import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl;
import org.jetbrains.jet.lang.resolve.OverloadResolver;
import org.jetbrains.jet.lang.resolve.OverrideResolver;
import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver;
......@@ -81,6 +82,7 @@ public class InjectorForTopDownAnalyzer {
OverloadingConflictResolver overloadingConflictResolver = new OverloadingConflictResolver();
ImportsResolver importsResolver = new ImportsResolver();
DelegationResolver delegationResolver = new DelegationResolver();
NamespaceFactoryImpl namespaceFactoryImpl = new NamespaceFactoryImpl();
OverloadResolver overloadResolver = new OverloadResolver();
OverrideResolver overrideResolver = new OverrideResolver();
TypeHierarchyResolver typeHierarchyResolver = new TypeHierarchyResolver();
......@@ -93,6 +95,7 @@ public class InjectorForTopDownAnalyzer {
this.topDownAnalyzer.setDeclarationsChecker(declarationsChecker);
this.topDownAnalyzer.setDelegationResolver(delegationResolver);
this.topDownAnalyzer.setModuleDescriptor(moduleDescriptor);
this.topDownAnalyzer.setNamespaceFactory(namespaceFactoryImpl);
this.topDownAnalyzer.setOverloadResolver(overloadResolver);
this.topDownAnalyzer.setOverrideResolver(overrideResolver);
this.topDownAnalyzer.setTopDownAnalysisParameters(topDownAnalysisParameters);
......@@ -142,16 +145,19 @@ public class InjectorForTopDownAnalyzer {
delegationResolver.setContext(topDownAnalysisContext);
namespaceFactoryImpl.setConfiguration(moduleConfiguration);
namespaceFactoryImpl.setContext(topDownAnalysisContext);
namespaceFactoryImpl.setModuleDescriptor(moduleDescriptor);
overloadResolver.setContext(topDownAnalysisContext);
overrideResolver.setContext(topDownAnalysisContext);
overrideResolver.setTopDownAnalysisParameters(topDownAnalysisParameters);
typeHierarchyResolver.setConfiguration(moduleConfiguration);
typeHierarchyResolver.setContext(topDownAnalysisContext);
typeHierarchyResolver.setDescriptorResolver(descriptorResolver);
typeHierarchyResolver.setImportsResolver(importsResolver);
typeHierarchyResolver.setModuleDescriptor(moduleDescriptor);
typeHierarchyResolver.setNamespaceFactory(namespaceFactoryImpl);
}
......
......@@ -18,6 +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;
......@@ -125,6 +126,81 @@ public class FqName {
return shortName;
}
private interface WalkCallback {
void segment(@NotNull String shortName, @NotNull FqName fqName);
}
@NotNull
public List<FqName> path() {
final List<FqName> path = Lists.newArrayList();
path.add(ROOT);
walk(new WalkCallback() {
@Override
public void segment(@NotNull String shortName, @NotNull FqName 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 FqName fqName) {
path.add(shortName);
}
});
return path;
}
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) {
......
/*
* 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 org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptorImpl;
/**
* @author Stepan Koltsov
*/
public interface NamespaceFactory {
@NotNull
NamespaceDescriptorImpl createNamespaceDescriptorPathIfNeeded(@NotNull FqName fqName);
}
/*
* 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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.ModuleConfiguration;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptorParent;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespaceHeader;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import javax.inject.Inject;
import java.util.Collections;
import static org.jetbrains.jet.lang.resolve.BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLUTION_SCOPE;
/**
* @author Stepan Koltsov
*/
public class NamespaceFactoryImpl implements NamespaceFactory {
private ModuleDescriptor moduleDescriptor;
private TopDownAnalysisContext context;
private ModuleConfiguration configuration;
@Inject
public void setModuleDescriptor(ModuleDescriptor moduleDescriptor) {
this.moduleDescriptor = moduleDescriptor;
}
@Inject
public void setContext(TopDownAnalysisContext context) {
this.context = context;
}
@Inject
public void setConfiguration(ModuleConfiguration configuration) {
this.configuration = configuration;
}
public NamespaceDescriptorImpl createNamespaceDescriptorPathIfNeeded(JetFile file, JetScope outerScope) {
JetNamespaceHeader namespaceHeader = file.getNamespaceHeader();
if (moduleDescriptor.getRootNs() == null) {
createNamespaceDescriptorIfNeeded(null, moduleDescriptor, "<root>", true);
}
NamespaceDescriptorParent currentOwner = moduleDescriptor.getRootNs();
if (currentOwner == null) {
throw new IllegalStateException("must be initialized 5 lines above");
}
for (JetSimpleNameExpression nameExpression : namespaceHeader.getParentNamespaceNames()) {
String namespaceName = JetPsiUtil.safeName(nameExpression.getReferencedName());
NamespaceDescriptorImpl namespaceDescriptor = createNamespaceDescriptorIfNeeded(null, currentOwner, namespaceName, false);
currentOwner = namespaceDescriptor;
context.getTrace().record(REFERENCE_TARGET, nameExpression, currentOwner);
context.getTrace().record(RESOLUTION_SCOPE, nameExpression, outerScope);
outerScope = namespaceDescriptor.getMemberScope();
}
String name = JetPsiUtil.safeName(namespaceHeader.getName());
context.getTrace().record(RESOLUTION_SCOPE, namespaceHeader, outerScope);
return createNamespaceDescriptorIfNeeded(file, currentOwner, name, false);
}
@Override
@NotNull
public NamespaceDescriptorImpl createNamespaceDescriptorPathIfNeeded(@NotNull FqName fqName) {
NamespaceDescriptorParent owner = moduleDescriptor;
for (FqName pathElement : fqName.path()) {
owner = createNamespaceDescriptorIfNeeded(null,
owner, pathElement.isRoot() ? "<root>" : pathElement.shortName(), pathElement.isRoot());
}
return (NamespaceDescriptorImpl) owner;
}
@NotNull
public NamespaceDescriptorImpl createNamespaceDescriptorIfNeeded(@Nullable JetFile file, @NotNull NamespaceDescriptorParent owner, @NotNull String name, boolean root) {
FqName fqName;
NamespaceDescriptorImpl namespaceDescriptor;
if (root) {
if (!(owner instanceof ModuleDescriptor)) {
throw new IllegalStateException();
}
fqName = FqName.ROOT;
namespaceDescriptor = ((ModuleDescriptor) owner).getRootNs();
}
else {
FqName ownerFqName = DescriptorUtils.getFQName(owner);
fqName = ownerFqName.child(name);
namespaceDescriptor = ((NamespaceDescriptorImpl) owner).getNamespace(name);
}
if (namespaceDescriptor == null) {
namespaceDescriptor = new NamespaceDescriptorImpl(
owner,
Collections.<AnnotationDescriptor>emptyList(), // TODO: annotations
name
);
context.getTrace().record(FQNAME_TO_NAMESPACE_DESCRIPTOR, fqName, namespaceDescriptor);
WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Namespace member scope");
scope.changeLockLevel(WritableScope.LockLevel.BOTH);
namespaceDescriptor.initialize(scope);
configuration.extendNamespaceScope(context.getTrace(), namespaceDescriptor, scope);
owner.addNamespace(namespaceDescriptor);
if (file != null) {
context.getTrace().record(BindingContext.NAMESPACE, file, namespaceDescriptor);
}
}
if (file != null) {
context.getTrace().record(BindingContext.FILE_TO_NAMESPACE, file, namespaceDescriptor);
}
return namespaceDescriptor;
}
}
......@@ -66,6 +66,8 @@ public class TopDownAnalyzer {
private ModuleConfiguration configuration;
@NotNull
private ModuleDescriptor moduleDescriptor;
@NotNull
private NamespaceFactoryImpl namespaceFactory;
private BodyResolver bodyResolver;
private ControlFlowAnalyzer controlFlowAnalyzer;
......@@ -116,6 +118,11 @@ public class TopDownAnalyzer {
this.moduleDescriptor = moduleDescriptor;
}
@Inject
public void setNamespaceFactory(@NotNull NamespaceFactoryImpl namespaceFactory) {
this.namespaceFactory = namespaceFactory;
}
@Inject
public void setBodyResolver(BodyResolver bodyResolver) {
this.bodyResolver = bodyResolver;
......@@ -288,7 +295,7 @@ public class TopDownAnalyzer {
// Import the lang package
scope.importScope(JetStandardLibrary.getInstance().getLibraryScope());
NamespaceDescriptorImpl rootNs = typeHierarchyResolver.createNamespaceDescriptorIfNeeded(null, moduleDescriptor, "<root>", true);
NamespaceDescriptorImpl rootNs = namespaceFactory.createNamespaceDescriptorPathIfNeeded(FqName.ROOT);
// Import a scope that contains all top-level namespaces that come from dependencies
// This makes the namespaces visible at all, does not import themselves
......
......@@ -55,9 +55,7 @@ public class TypeHierarchyResolver {
@NotNull
private DescriptorResolver descriptorResolver;
@NotNull
private ModuleConfiguration configuration;
@NotNull
private ModuleDescriptor moduleDescriptor;
private NamespaceFactoryImpl namespaceFactory;
// state
private LinkedList<MutableClassDescriptor> topologicalOrder;
......@@ -78,14 +76,11 @@ public class TypeHierarchyResolver {
}
@Inject
public void setConfiguration(@NotNull ModuleConfiguration configuration) {
this.configuration = configuration;
public void setNamespaceFactory(@NotNull NamespaceFactoryImpl namespaceFactory) {
this.namespaceFactory = namespaceFactory;
}
@Inject
public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
this.moduleDescriptor = moduleDescriptor;
}
public void process(@NotNull JetScope outerScope, @NotNull NamespaceLikeBuilder owner, @NotNull Collection<? extends PsiElement> declarations) {
collectNamespacesAndClassifiers(outerScope, outerScope, owner, declarations); // namespaceScopes, classes
......@@ -117,7 +112,7 @@ public class TypeHierarchyResolver {
declaration.accept(new JetVisitorVoid() {
@Override
public void visitJetFile(JetFile file) {
NamespaceDescriptorImpl namespaceDescriptor = createNamespaceDescriptorPathIfNeeded(file, outerScope);
NamespaceDescriptorImpl namespaceDescriptor = namespaceFactory.createNamespaceDescriptorPathIfNeeded(file, outerScope);
context.getNamespaceDescriptors().put(file, namespaceDescriptor);
WriteThroughScope namespaceScope = new WriteThroughScope(outerScope, namespaceDescriptor.getMemberScope(), new TraceBasedRedeclarationHandler(context.getTrace()));
......@@ -231,79 +226,6 @@ public class TypeHierarchyResolver {
}
}
private NamespaceDescriptorImpl createNamespaceDescriptorPathIfNeeded(JetFile file, JetScope outerScope) {
JetNamespaceHeader namespaceHeader = file.getNamespaceHeader();
if (moduleDescriptor.getRootNs() == null) {
createNamespaceDescriptorIfNeeded(null, moduleDescriptor, "<root>", true);
}
NamespaceDescriptorParent currentOwner = moduleDescriptor.getRootNs();
if (currentOwner == null) {
throw new IllegalStateException("must be initialized 5 lines above");
}
for (JetSimpleNameExpression nameExpression : namespaceHeader.getParentNamespaceNames()) {
String namespaceName = JetPsiUtil.safeName(nameExpression.getReferencedName());
NamespaceDescriptorImpl namespaceDescriptor = createNamespaceDescriptorIfNeeded(null, currentOwner, namespaceName, false);
currentOwner = namespaceDescriptor;
context.getTrace().record(REFERENCE_TARGET, nameExpression, currentOwner);
context.getTrace().record(RESOLUTION_SCOPE, nameExpression, outerScope);
outerScope = namespaceDescriptor.getMemberScope();
}
String name = JetPsiUtil.safeName(namespaceHeader.getName());
context.getTrace().record(RESOLUTION_SCOPE, namespaceHeader, outerScope);
return createNamespaceDescriptorIfNeeded(file, currentOwner, name, false);
}
@NotNull
public NamespaceDescriptorImpl createNamespaceDescriptorIfNeeded(@Nullable JetFile file, @NotNull NamespaceDescriptorParent owner, @NotNull String name, boolean root) {
FqName fqName;
NamespaceDescriptorImpl namespaceDescriptor;
if (root) {
if (!(owner instanceof ModuleDescriptor)) {
throw new IllegalStateException();
}
fqName = FqName.ROOT;
namespaceDescriptor = ((ModuleDescriptor) owner).getRootNs();
}
else {
FqName ownerFqName = DescriptorUtils.getFQName(owner);
fqName = ownerFqName.child(name);
namespaceDescriptor = ((NamespaceDescriptorImpl) owner).getNamespace(name);
}
if (namespaceDescriptor == null) {
namespaceDescriptor = new NamespaceDescriptorImpl(
owner,
Collections.<AnnotationDescriptor>emptyList(), // TODO: annotations
name
);
context.getTrace().record(FQNAME_TO_NAMESPACE_DESCRIPTOR, fqName, namespaceDescriptor);
WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Namespace member scope");
scope.changeLockLevel(WritableScope.LockLevel.BOTH);
namespaceDescriptor.initialize(scope);
configuration.extendNamespaceScope(context.getTrace(), namespaceDescriptor, scope);
owner.addNamespace(namespaceDescriptor);
if (file != null) {
context.getTrace().record(BindingContext.NAMESPACE, file, namespaceDescriptor);
}
}
if (file != null) {
context.getTrace().record(BindingContext.FILE_TO_NAMESPACE, file, namespaceDescriptor);
}
return namespaceDescriptor;
}
@NotNull
private ClassKind getClassKind(@NotNull JetClass jetClass) {
if (jetClass.isTrait()) return ClassKind.TRAIT;
......
/*
* 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;
import com.google.common.collect.Lists;
import org.jetbrains.jet.lang.resolve.FqName;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
/**
* @author Stepan Koltsov
*/
public class FqNameTest {
@Test
public void pathRoot() {
List<FqName> path = new FqName("").path();
Assert.assertEquals(1, path.size());
Assert.assertEquals("", path.get(0).getFqName());
}
@Test
public void pathLevel1() {
List<FqName> path = new FqName("com").path();
Assert.assertEquals(2, path.size());
Assert.assertEquals("", path.get(0).getFqName());
Assert.assertEquals("com", path.get(1).getFqName());
Assert.assertEquals("com", path.get(1).shortName());
Assert.assertEquals("", path.get(1).parent().getFqName());
}
@Test
public void pathLevel2() {
List<FqName> path = new FqName("com.jetbrains").path();
Assert.assertEquals(3, path.size());
Assert.assertEquals("", path.get(0).getFqName());
Assert.assertEquals("com", path.get(1).getFqName());
Assert.assertEquals("com", path.get(1).shortName());
Assert.assertEquals("", path.get(1).parent().getFqName());
Assert.assertEquals("com.jetbrains", path.get(2).getFqName());
Assert.assertEquals("jetbrains", path.get(2).shortName());
Assert.assertEquals("com", path.get(2).parent().getFqName());
}
@Test
public void pathLevel3() {
List<FqName> path = new FqName("com.jetbrains.jet").path();
Assert.assertEquals(4, path.size());
Assert.assertEquals("", path.get(0).getFqName());
Assert.assertEquals("com", path.get(1).getFqName());
Assert.assertEquals("com", path.get(1).shortName());
Assert.assertEquals("", path.get(1).parent().getFqName());
Assert.assertEquals("com.jetbrains", path.get(2).getFqName());
Assert.assertEquals("jetbrains", path.get(2).shortName());
Assert.assertEquals("com", path.get(2).parent().getFqName());
Assert.assertEquals("com.jetbrains.jet", path.get(3).getFqName());
Assert.assertEquals("jet", path.get(3).shortName());
Assert.assertEquals("com.jetbrains", path.get(3).parent().getFqName());
}
@Test
public void pathSegments() {
Assert.assertEquals(Lists.newArrayList(), new FqName("").pathSegments());
for (String name : new String[] { "com", "com.jetbrains", "com.jetbrains.jet" }) {
List<String> segments = new FqName(name).pathSegments();
Assert.assertEquals(Arrays.asList(name.split("\\.")), segments);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册