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.psi;
018
019 import com.intellij.lang.ASTNode;
020 import com.intellij.openapi.project.Project;
021 import com.intellij.openapi.util.Pair;
022 import com.intellij.psi.PsiElement;
023 import com.intellij.psi.PsiFileFactory;
024 import com.intellij.psi.util.PsiTreeUtil;
025 import com.intellij.util.LocalTimeCounter;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.jet.lang.resolve.ImportPath;
029 import org.jetbrains.jet.lang.resolve.name.Name;
030 import org.jetbrains.jet.lexer.JetKeywordToken;
031 import org.jetbrains.jet.lexer.JetTokens;
032 import org.jetbrains.jet.plugin.JetFileType;
033
034 import java.util.List;
035
036 public class JetPsiFactory {
037
038 public static ASTNode createValNode(Project project) {
039 JetProperty property = createProperty(project, "val x = 1");
040 return property.getValOrVarNode();
041 }
042
043 public static ASTNode createVarNode(Project project) {
044 JetProperty property = createProperty(project, "var x = 1");
045 return property.getValOrVarNode();
046 }
047
048 public static ASTNode createValOrVarNode(Project project, String text) {
049 return createParameterList(project, "(" + text + " int x)").getParameters().get(0).getValOrVarNode();
050 }
051
052 public static JetExpression createExpression(Project project, String text) {
053 JetProperty property = createProperty(project, "val x = " + text);
054 return property.getInitializer();
055 }
056
057 public static JetValueArgumentList createCallArguments(Project project, String text) {
058 JetProperty property = createProperty(project, "val x = foo" + text);
059 JetExpression initializer = property.getInitializer();
060 JetCallExpression callExpression = (JetCallExpression) initializer;
061 return callExpression.getValueArgumentList();
062 }
063
064 public static JetTypeReference createType(Project project, String type) {
065 JetProperty property = createProperty(project, "val x : " + type);
066 return property.getTypeRef();
067 }
068
069 @NotNull
070 public static PsiElement createStar(Project project) {
071 PsiElement star = createType(project, "List<*>").findElementAt(5);
072 assert star != null;
073 return star;
074 }
075
076 @NotNull
077 public static PsiElement createComma(Project project) {
078 PsiElement comma = createType(project, "T<X, Y>").findElementAt(3);
079 assert comma != null;
080 return comma;
081 }
082
083 //the pair contains the first and the last elements of a range
084 public static Pair<PsiElement, PsiElement> createColonAndWhiteSpaces(Project project) {
085 JetProperty property = createProperty(project, "val x : Int");
086 return Pair.create(property.findElementAt(5), property.findElementAt(7));
087 }
088
089 //the pair contains the first and the last elements of a range
090 public static Pair<PsiElement, PsiElement> createTypeWhiteSpaceAndColon(Project project, String type) {
091 JetProperty property = createProperty(project, "val x: " + type);
092 return Pair.create(property.findElementAt(5), (PsiElement) property.getTypeRef());
093 }
094
095 public static ASTNode createColonNode(Project project) {
096 JetProperty property = createProperty(project, "val x: Int");
097 return property.getNode().findChildByType(JetTokens.COLON);
098 }
099
100 @NotNull
101 public static PsiElement createSemicolon(Project project) {
102 JetProperty property = createProperty(project, "val x: Int;");
103 PsiElement semicolon = property.findElementAt(10);
104 assert semicolon != null;
105 return semicolon;
106 }
107
108 public static PsiElement createWhiteSpace(Project project) {
109 return createWhiteSpace(project, " ");
110 }
111
112 private static PsiElement createWhiteSpace(Project project, String text) {
113 JetProperty property = createProperty(project, "val" + text + "x");
114 return property.findElementAt(3);
115 }
116
117 public static PsiElement createNewLine(Project project) {
118 return createWhiteSpace(project, "\n");
119 }
120
121 public static JetClass createClass(Project project, String text) {
122 return createDeclaration(project, text, JetClass.class);
123 }
124
125 @NotNull
126 public static JetFile createFile(Project project, String text) {
127 return createFile(project, "dummy.jet", text);
128 }
129
130 @NotNull
131 public static JetFile createFile(Project project, String fileName, String text) {
132 return (JetFile) PsiFileFactory.getInstance(project).createFileFromText(fileName, JetFileType.INSTANCE, text,
133 LocalTimeCounter.currentTime(), false);
134 }
135
136 @NotNull
137 public static JetFile createPhysicalFile(Project project, String fileName, String text) {
138 return (JetFile) PsiFileFactory.getInstance(project).createFileFromText(fileName, JetFileType.INSTANCE, text,
139 LocalTimeCounter.currentTime(), true);
140 }
141
142 public static JetProperty createProperty(Project project, String name, String type, boolean isVar, @Nullable String initializer) {
143 String text = (isVar ? "var " : "val ") + name + (type != null ? ":" + type : "") + (initializer == null ? "" : " = " + initializer);
144 return createProperty(project, text);
145 }
146
147 public static JetProperty createProperty(Project project, String name, String type, boolean isVar) {
148 return createProperty(project, name, type, isVar, null);
149 }
150
151 public static JetProperty createProperty(Project project, String text) {
152 return createDeclaration(project, text, JetProperty.class);
153 }
154
155 private static <T> T createDeclaration(Project project, String text, Class<T> clazz) {
156 JetFile file = createFile(project, text);
157 List<JetDeclaration> dcls = file.getDeclarations();
158 assert dcls.size() == 1 : dcls.size() + " declarations in " + text;
159 @SuppressWarnings("unchecked")
160 T result = (T) dcls.get(0);
161 return result;
162 }
163
164 public static PsiElement createNameIdentifier(Project project, String name) {
165 return createProperty(project, name, null, false).getNameIdentifier();
166 }
167
168 public static JetSimpleNameExpression createSimpleName(Project project, String name) {
169 return (JetSimpleNameExpression) createProperty(project, name, null, false, name).getInitializer();
170 }
171
172 public static PsiElement createIdentifier(Project project, String name) {
173 return createSimpleName(project, name).getIdentifier();
174 }
175
176 public static JetNamedFunction createFunction(Project project, String funDecl) {
177 return createDeclaration(project, funDecl, JetNamedFunction.class);
178 }
179
180 public static JetModifierList createModifierList(Project project, JetKeywordToken modifier) {
181 String text = modifier.getValue() + " val x";
182 JetProperty property = createProperty(project, text);
183 return property.getModifierList();
184 }
185
186 public static JetModifierList createConstructorModifierList(Project project, JetKeywordToken modifier) {
187 JetClass aClass = createClass(project, "class C " + modifier.getValue() + " (){}");
188 return aClass.getPrimaryConstructorModifierList();
189 }
190
191 public static JetExpression createEmptyBody(Project project) {
192 JetNamedFunction function = createFunction(project, "fun foo() {}");
193 return function.getBodyExpression();
194 }
195
196 public static JetClassBody createEmptyClassBody(Project project) {
197 JetClass aClass = createClass(project, "class A(){}");
198 return aClass.getBody();
199 }
200
201 public static JetParameter createParameter(Project project, String name, String type) {
202 JetNamedFunction function = createFunction(project, "fun foo(" + name + " : " + type + ") {}");
203 return function.getValueParameters().get(0);
204 }
205
206 public static JetParameterList createParameterList(Project project, String text) {
207 JetNamedFunction function = createFunction(project, "fun foo" + text + "{}");
208 return function.getValueParameterList();
209 }
210
211 @NotNull
212 public static JetWhenEntry createWhenEntry(@NotNull Project project, @NotNull String entryText) {
213 JetNamedFunction function = createFunction(project, "fun foo() { when(12) { " + entryText + " } }");
214 JetWhenEntry whenEntry = PsiTreeUtil.findChildOfType(function, JetWhenEntry.class);
215
216 assert whenEntry != null : "Couldn't generate when entry";
217 assert entryText.equals(whenEntry.getText()) : "Generate when entry text differs from the given text";
218
219 return whenEntry;
220 }
221
222 @NotNull
223 public static JetImportDirective createImportDirective(Project project, @NotNull String path) {
224 return createImportDirective(project, new ImportPath(path));
225 }
226
227 @NotNull
228 public static JetImportDirective createImportDirective(Project project, @NotNull ImportPath importPath) {
229 if (importPath.fqnPart().isRoot()) {
230 throw new IllegalArgumentException("import path must not be empty");
231 }
232
233 StringBuilder importDirectiveBuilder = new StringBuilder("import ");
234 importDirectiveBuilder.append(importPath.getPathStr());
235
236 Name alias = importPath.getAlias();
237 if (alias != null) {
238 importDirectiveBuilder.append(" as ").append(alias.asString());
239 }
240
241 JetFile namespace = createFile(project, importDirectiveBuilder.toString());
242 return namespace.getImportDirectives().iterator().next();
243 }
244
245 public static PsiElement createPrimaryConstructor(Project project) {
246 JetClass aClass = createClass(project, "class A()");
247 return aClass.findElementAt(7).getParent();
248 }
249
250 public static JetSimpleNameExpression createClassLabel(Project project, @NotNull String labelName) {
251 JetThisExpression expression = (JetThisExpression) createExpression(project, "this@" + labelName);
252 return expression.getTargetLabel();
253 }
254
255 public static JetExpression createFieldIdentifier(Project project, @NotNull String fieldName) {
256 return createExpression(project, "$" + fieldName);
257 }
258
259 @NotNull
260 public static JetBinaryExpression createBinaryExpression(Project project, @NotNull String lhs, @NotNull String op, @NotNull String rhs) {
261 return (JetBinaryExpression) createExpression(project, lhs + " " + op + " " + rhs);
262 }
263
264 @NotNull
265 public static JetBinaryExpression createBinaryExpression(Project project, @Nullable JetExpression lhs, @NotNull String op, @Nullable JetExpression rhs) {
266 return createBinaryExpression(project, JetPsiUtil.getText(lhs), op, JetPsiUtil.getText(rhs));
267 }
268
269 public static JetTypeCodeFragment createTypeCodeFragment(Project project, String text, PsiElement context) {
270 return new JetTypeCodeFragmentImpl(project, "fragment.kt", text, context);
271 }
272
273 public static JetExpressionCodeFragment createExpressionCodeFragment(Project project, String text, PsiElement context) {
274 return new JetExpressionCodeFragmentImpl(project, "fragment.kt", text, context);
275 }
276
277 @NotNull
278 public static JetReturnExpression createReturn(Project project, @NotNull String text) {
279 return (JetReturnExpression) createExpression(project, "return " + text);
280 }
281
282 @NotNull
283 public static JetReturnExpression createReturn(Project project, @Nullable JetExpression expression) {
284 return createReturn(project, JetPsiUtil.getText(expression));
285 }
286
287 @NotNull
288 public static JetIfExpression createIf(Project project,
289 @Nullable JetExpression condition, @Nullable JetExpression thenExpr, @Nullable JetExpression elseExpr) {
290 return (JetIfExpression) createExpression(project, JetPsiUnparsingUtils.toIf(condition, thenExpr, elseExpr));
291 }
292
293 @NotNull
294 public static JetValueArgument createArgumentWithName(
295 @NotNull Project project,
296 @NotNull String name,
297 @NotNull JetExpression argumentExpression
298 ) {
299 return createCallArguments(project, "(" + name + " = " + argumentExpression.getText() + ")").getArguments().get(0);
300 }
301
302 public static class IfChainBuilder {
303 private final StringBuilder sb = new StringBuilder();
304 private boolean first = true;
305 private boolean frozen = false;
306
307 public IfChainBuilder() {
308 }
309
310 @NotNull
311 public IfChainBuilder ifBranch(@NotNull String conditionText, @NotNull String expressionText) {
312 if (first) {
313 first = false;
314 } else {
315 sb.append("else ");
316 }
317
318 sb.append("if (").append(conditionText).append(") ").append(expressionText).append("\n");
319 return this;
320 }
321
322 @NotNull
323 public IfChainBuilder ifBranch(@NotNull JetExpression condition, @NotNull JetExpression expression) {
324 return ifBranch(condition.getText(), expression.getText());
325 }
326
327 @NotNull
328 public IfChainBuilder elseBranch(@NotNull String expressionText) {
329 sb.append("else ").append(expressionText);
330 return this;
331 }
332
333 @NotNull
334 public IfChainBuilder elseBranch(@Nullable JetExpression expression) {
335 return elseBranch(JetPsiUtil.getText(expression));
336 }
337
338 @NotNull
339 public JetIfExpression toExpression(Project project) {
340 if (!frozen) {
341 frozen = true;
342 }
343 return (JetIfExpression) createExpression(project, sb.toString());
344 }
345 }
346
347 public static class WhenBuilder {
348 private final StringBuilder sb = new StringBuilder("when ");
349 private boolean frozen = false;
350 private boolean inCondition = false;
351
352 public WhenBuilder() {
353 this((String)null);
354 }
355
356 public WhenBuilder(@Nullable String subjectText) {
357 if (subjectText != null) {
358 sb.append("(").append(subjectText).append(") ");
359 }
360 sb.append("{\n");
361 }
362
363 public WhenBuilder(@Nullable JetExpression subject) {
364 this(subject != null ? subject.getText() : null);
365 }
366
367 @NotNull
368 public WhenBuilder condition(@NotNull String text) {
369 assert !frozen;
370
371 if (!inCondition) {
372 inCondition = true;
373 } else {
374 sb.append(", ");
375 }
376 sb.append(text);
377
378 return this;
379 }
380
381 @NotNull
382 public WhenBuilder condition(@Nullable JetExpression expression) {
383 return condition(JetPsiUtil.getText(expression));
384 }
385
386 @NotNull
387 public WhenBuilder pattern(@NotNull String typeReferenceText, boolean negated) {
388 return condition((negated ? "!is" : "is") + " " + typeReferenceText);
389 }
390
391 @NotNull
392 public WhenBuilder pattern(@Nullable JetTypeReference typeReference, boolean negated) {
393 return pattern(JetPsiUtil.getText(typeReference), negated);
394 }
395
396 @NotNull
397 public WhenBuilder range(@NotNull String argumentText, boolean negated) {
398 return condition((negated ? "!in" : "in") + " " + argumentText);
399 }
400
401 @NotNull
402 public WhenBuilder range(@Nullable JetExpression argument, boolean negated) {
403 return range(JetPsiUtil.getText(argument), negated);
404 }
405
406 @NotNull
407 public WhenBuilder branchExpression(@NotNull String expressionText) {
408 assert !frozen;
409 assert inCondition;
410
411 inCondition = false;
412 sb.append(" -> ").append(expressionText).append("\n");
413
414 return this;
415 }
416
417 @NotNull
418 public WhenBuilder branchExpression(@Nullable JetExpression expression) {
419 return branchExpression(JetPsiUtil.getText(expression));
420 }
421
422 @NotNull
423 public WhenBuilder entry(@NotNull String entryText) {
424 assert !frozen;
425 assert !inCondition;
426
427 sb.append(entryText).append("\n");
428
429 return this;
430 }
431
432 @NotNull
433 public WhenBuilder entry(@Nullable JetWhenEntry whenEntry) {
434 return entry(JetPsiUtil.getText(whenEntry));
435 }
436
437 @NotNull
438 public WhenBuilder elseEntry(@NotNull String text) {
439 return entry("else -> " + text);
440 }
441
442 @NotNull
443 public WhenBuilder elseEntry(@Nullable JetExpression expression) {
444 return elseEntry(JetPsiUtil.getText(expression));
445 }
446
447 @NotNull
448 public JetWhenExpression toExpression(Project project) {
449 if (!frozen) {
450 sb.append("}");
451 frozen = true;
452 }
453 return (JetWhenExpression) createExpression(project, sb.toString());
454 }
455 }
456
457 public static JetExpression createFunctionBody(Project project, @NotNull String bodyText) {
458 JetFunction func = createFunction(project, "fun foo() {\n" + bodyText + "\n}");
459 return func.getBodyExpression();
460 }
461
462 public static JetClassObject createEmptyClassObject(Project project) {
463 JetClass klass = createClass(project, "class foo { class object { } }");
464 return klass.getClassObject();
465 }
466 }