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