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    
017    package org.jetbrains.jet.lang.resolve.name;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.openapi.util.text.StringUtil;
021    import org.jetbrains.annotations.NotNull;
022    
023    import java.util.List;
024    
025    public 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    }