001 /*
002 * Copyright 2010-2015 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.name;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.kotlin.utils.UtilsPackage;
021
022 import java.util.ArrayList;
023 import java.util.List;
024
025 public final class FqName extends FqNameBase {
026
027 @NotNull
028 public static FqName fromSegments(@NotNull List<String> names) {
029 return new FqName(UtilsPackage.join(names, "."));
030 }
031
032 public static final FqName ROOT = new FqName("");
033
034 @NotNull
035 private final FqNameUnsafe fqName;
036
037 // cache
038 private transient FqName parent;
039
040 public FqName(@NotNull String fqName) {
041 this.fqName = new FqNameUnsafe(fqName, this);
042
043 validateFqName();
044 }
045
046 public FqName(@NotNull FqNameUnsafe fqName) {
047 this.fqName = fqName;
048
049 validateFqName();
050 }
051
052 private FqName(@NotNull FqNameUnsafe fqName, FqName parent) {
053 this.fqName = fqName;
054 this.parent = parent;
055
056 validateFqName();
057 }
058
059
060 private void validateFqName() {
061 if (!isValidAfterUnsafeCheck(fqName.asString())) {
062 throw new IllegalArgumentException("incorrect fq name: " + fqName);
063 }
064 }
065
066 /*package*/ static boolean isValidAfterUnsafeCheck(@NotNull String qualifiedName) {
067 // TODO: There's a valid name with escape char ``
068 return qualifiedName.indexOf('<') < 0;
069 }
070
071 @Override
072 @NotNull
073 public String asString() {
074 return fqName.asString();
075 }
076
077 @NotNull
078 public FqNameUnsafe toUnsafe() {
079 return fqName;
080 }
081
082 public boolean isRoot() {
083 return fqName.isRoot();
084 }
085
086 @NotNull
087 public FqName parent() {
088 if (parent != null) {
089 return parent;
090 }
091
092 if (isRoot()) {
093 throw new IllegalStateException("root");
094 }
095
096 parent = new FqName(fqName.parent());
097
098 return parent;
099 }
100
101 @NotNull
102 public FqName child(@NotNull Name name) {
103 return new FqName(fqName.child(name), this);
104 }
105
106 @NotNull
107 public Name shortName() {
108 return fqName.shortName();
109 }
110
111 @Override
112 @NotNull
113 public Name shortNameOrSpecial() {
114 return fqName.shortNameOrSpecial();
115 }
116
117 @NotNull
118 public List<FqName> path() {
119 final List<FqName> path = new ArrayList<FqName>();
120 path.add(ROOT);
121 fqName.walk(new FqNameUnsafe.WalkCallback() {
122 @Override
123 public void segment(@NotNull Name shortName, @NotNull FqNameUnsafe fqName) {
124 // TODO: do not validate
125 path.add(new FqName(fqName));
126 }
127 });
128 return path;
129 }
130
131 @Override
132 @NotNull
133 public List<Name> pathSegments() {
134 return fqName.pathSegments();
135 }
136
137 public boolean firstSegmentIs(@NotNull Name segment) {
138 return fqName.firstSegmentIs(segment);
139 }
140
141 public boolean lastSegmentIs(@NotNull Name segment) {
142 return fqName.lastSegmentIs(segment);
143 }
144
145 public boolean isAncestorOf(@NotNull FqName other) {
146 String thisString = this.asString();
147 String otherString = other.asString();
148 return otherString.equals(thisString) || otherString.startsWith(thisString + ".");
149 }
150
151 @NotNull
152 public static FqName topLevel(@NotNull Name shortName) {
153 return new FqName(FqNameUnsafe.topLevel(shortName));
154 }
155
156
157 @Override
158 public String toString() {
159 return fqName.toString();
160 }
161
162 @Override
163 public boolean equals(Object o) {
164 if (this == o) return true;
165 if (!(o instanceof FqName)) return false;
166
167 FqName otherFqName = (FqName) o;
168
169 if (!fqName.equals(otherFqName.fqName)) return false;
170
171 return true;
172 }
173
174 @Override
175 public int hashCode() {
176 return fqName.hashCode();
177 }
178 }