From 4c8cd6ca5c764e2f162899d4813f5b5edfe00bc7 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 15 Mar 2012 17:30:29 +0400 Subject: [PATCH] NamespaceFactory * extract NamespaceFactory from TypeHierarchyResolver * implement NamespaceFactory.createNamespaceDescriptorPathIfNeeded(FqName) * FqName .path() and .pathSegments() utilities --- .../jet/di/InjectorForTopDownAnalyzer.java | 10 +- .../jetbrains/jet/lang/resolve/FqName.java | 76 +++++++++ .../jet/lang/resolve/NamespaceFactory.java | 28 ++++ .../lang/resolve/NamespaceFactoryImpl.java | 152 ++++++++++++++++++ .../jet/lang/resolve/TopDownAnalyzer.java | 9 +- .../lang/resolve/TypeHierarchyResolver.java | 88 +--------- .../tests/org/jetbrains/jet/FqNameTest.java | 88 ++++++++++ 7 files changed, 365 insertions(+), 86 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/NamespaceFactory.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/NamespaceFactoryImpl.java create mode 100644 compiler/tests/org/jetbrains/jet/FqNameTest.java diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzer.java index ebc497c2867..6589a530abc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzer.java @@ -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); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/FqName.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/FqName.java index 4068f0fccf3..a4b5c7b002e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/FqName.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/FqName.java @@ -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 path() { + final List 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 pathSegments() { + final List 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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/NamespaceFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/NamespaceFactory.java new file mode 100644 index 00000000000..53ae6be294f --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/NamespaceFactory.java @@ -0,0 +1,28 @@ +/* + * 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); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/NamespaceFactoryImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/NamespaceFactoryImpl.java new file mode 100644 index 00000000000..7547a960979 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/NamespaceFactoryImpl.java @@ -0,0 +1,152 @@ +/* + * 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, "", 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() ? "" : 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.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; + } + + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 1b6e1b055d7..d5685e18866 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -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, "", 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 diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index 63a49dd6785..8294230c144 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -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 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 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, "", 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.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; diff --git a/compiler/tests/org/jetbrains/jet/FqNameTest.java b/compiler/tests/org/jetbrains/jet/FqNameTest.java new file mode 100644 index 00000000000..5cb2b766d07 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/FqNameTest.java @@ -0,0 +1,88 @@ +/* + * 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 path = new FqName("").path(); + Assert.assertEquals(1, path.size()); + Assert.assertEquals("", path.get(0).getFqName()); + } + + @Test + public void pathLevel1() { + List 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 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 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 segments = new FqName(name).pathSegments(); + Assert.assertEquals(Arrays.asList(name.split("\\.")), segments); + } + } + +}