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.k2js.translate.intrinsic.functions.patterns;
018
019 import com.google.common.collect.Lists;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.jet.lang.descriptors.*;
022 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
023 import org.jetbrains.jet.lang.resolve.OverrideResolver;
024 import org.jetbrains.jet.lang.resolve.name.Name;
025 import org.jetbrains.k2js.translate.context.Namer;
026 import org.jetbrains.k2js.translate.utils.TranslationUtils;
027
028 import java.util.Arrays;
029 import java.util.List;
030
031 public final class PatternBuilder {
032
033 @NotNull
034 private static final NamePredicate KOTLIN_NAME_PREDICATE = new NamePredicate("kotlin");
035
036 @NotNull
037 private static final Name KOTLIN_NAME = Name.identifier(Namer.KOTLIN_LOWER_NAME);
038
039 private PatternBuilder() {
040 }
041
042 @NotNull
043 public static DescriptorPredicate pattern(@NotNull NamePredicate checker, @NotNull String stringWithPattern) {
044 List<NamePredicate> checkers = Lists.newArrayList(checker);
045 checkers.addAll(parseStringAsCheckerList(stringWithPattern));
046 return pattern(checkers);
047 }
048
049 @NotNull
050 public static DescriptorPredicate pattern(@NotNull String stringWithPattern, @NotNull NamePredicate checker) {
051 List<NamePredicate> checkers = Lists.newArrayList(parseStringAsCheckerList(stringWithPattern));
052 checkers.add(checker);
053 return pattern(checkers);
054 }
055
056 @NotNull
057 public static DescriptorPredicate pattern(@NotNull String string) {
058 List<NamePredicate> checkers = parseStringAsCheckerList(string);
059 return pattern(checkers);
060 }
061
062 @NotNull
063 private static List<NamePredicate> parseStringAsCheckerList(@NotNull String stringWithPattern) {
064 String[] subPatterns = stringWithPattern.split("\\.");
065 List<NamePredicate> checkers = Lists.newArrayList();
066 for (String subPattern : subPatterns) {
067 String[] validNames = subPattern.split("\\|");
068 checkers.add(new NamePredicate(validNames));
069 }
070 return checkers;
071 }
072
073 @NotNull
074 private static DescriptorPredicate pattern(@NotNull List<NamePredicate> checkers) {
075 assert !checkers.isEmpty();
076 final List<NamePredicate> checkersWithPrefixChecker = Lists.newArrayList();
077 if (!checkers.get(0).apply(KOTLIN_NAME)) {
078 checkersWithPrefixChecker.add(KOTLIN_NAME_PREDICATE);
079 }
080
081 checkersWithPrefixChecker.addAll(checkers);
082
083 assert checkersWithPrefixChecker.size() > 1;
084
085 return new DescriptorPredicate() {
086 @Override
087 public boolean apply(@NotNull FunctionDescriptor descriptor) {
088 //TODO: no need to wrap if we check beforehand
089 try {
090 return doApply(descriptor);
091 }
092 catch (IllegalArgumentException e) {
093 return false;
094 }
095 }
096
097 private boolean doApply(@NotNull FunctionDescriptor descriptor) {
098 List<Name> nameParts = DescriptorUtils.getFqName(descriptor).pathSegments();
099 if (nameParts.size() != checkersWithPrefixChecker.size()) {
100 return false;
101 }
102 return allNamePartsValid(nameParts);
103 }
104
105 private boolean allNamePartsValid(@NotNull List<Name> nameParts) {
106 for (int i = 0; i < nameParts.size(); ++i) {
107 Name namePart = nameParts.get(i);
108 NamePredicate correspondingPredicate = checkersWithPrefixChecker.get(i);
109 if (!correspondingPredicate.apply(namePart)) {
110 return false;
111 }
112 }
113 return true;
114 }
115 };
116 }
117
118 @NotNull
119 public static DescriptorPredicate pattern(@NotNull NamePredicate... checkers) {
120 return pattern(Arrays.asList(checkers));
121 }
122
123 @NotNull
124 public static DescriptorPredicateImpl pattern(@NotNull String... names) {
125 return new DescriptorPredicateImpl(names);
126 }
127
128 public static class DescriptorPredicateImpl implements DescriptorPredicate {
129 private final String[] names;
130
131 private String receiverFqName;
132
133 private boolean checkOverridden;
134
135 public DescriptorPredicateImpl(String... names) {
136 this.names = names;
137 }
138
139 public DescriptorPredicateImpl isExtensionOf(String receiverFqName) {
140 this.receiverFqName = receiverFqName;
141 return this;
142 }
143
144 public DescriptorPredicateImpl checkOverridden() {
145 this.checkOverridden = true;
146 return this;
147 }
148
149 private boolean matches(@NotNull CallableDescriptor callable) {
150 DeclarationDescriptor descriptor = callable;
151 int nameIndex = names.length - 1;
152 while (true) {
153 if (nameIndex == -1) {
154 return false;
155 }
156
157 if (!descriptor.getName().asString().equals(names[nameIndex])) {
158 return false;
159 }
160
161 nameIndex--;
162 descriptor = descriptor.getContainingDeclaration();
163 if (descriptor instanceof PackageFragmentDescriptor) {
164 return nameIndex == 0 && names[0].equals(((PackageFragmentDescriptor) descriptor).getFqName().asString());
165 }
166 }
167 }
168
169 @Override
170 public boolean apply(@NotNull FunctionDescriptor functionDescriptor) {
171 ReceiverParameterDescriptor actualReceiver = functionDescriptor.getReceiverParameter();
172 if (actualReceiver != null) {
173 if (receiverFqName == null) return false;
174
175 String actualReceiverFqName = TranslationUtils.getJetTypeFqName(actualReceiver.getType());
176
177 if (!actualReceiverFqName.equals(receiverFqName)) return false;
178 }
179
180 if (!(functionDescriptor.getContainingDeclaration() instanceof ClassDescriptor)) {
181 return matches(functionDescriptor);
182 }
183
184 for (CallableMemberDescriptor real : OverrideResolver.getOverriddenDeclarations(functionDescriptor)) {
185 if (matches(real)) {
186 return true;
187 }
188 }
189
190 if (checkOverridden) {
191 for (CallableDescriptor overridden : OverrideResolver.getAllOverriddenDescriptors(functionDescriptor)) {
192 if (matches(overridden)) {
193 return true;
194 }
195 }
196 }
197
198 return false;
199 }
200 }
201 }