2 * Created by IntelliJ IDEA.
6 * To change template for new class use
7 * Code Style | Class Templates options (Tools | IDE Options).
9 package com.intellij.refactoring.introduceField;
11 import com.intellij.codeInsight.AnnotationUtil;
12 import com.intellij.codeInsight.ChangeContextUtil;
13 import com.intellij.codeInsight.TestUtil;
14 import com.intellij.codeInsight.highlighting.HighlightManager;
15 import com.intellij.ide.util.DirectoryChooserUtil;
16 import com.intellij.ide.util.PackageUtil;
17 import com.intellij.openapi.application.ApplicationManager;
18 import com.intellij.openapi.command.CommandProcessor;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.editor.Editor;
21 import com.intellij.openapi.editor.colors.EditorColors;
22 import com.intellij.openapi.editor.colors.EditorColorsManager;
23 import com.intellij.openapi.editor.markup.RangeHighlighter;
24 import com.intellij.openapi.editor.markup.TextAttributes;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.util.Pass;
27 import com.intellij.openapi.util.text.StringUtil;
28 import com.intellij.openapi.wm.WindowManager;
29 import com.intellij.psi.*;
30 import com.intellij.psi.codeStyle.CodeStyleManager;
31 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
32 import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
33 import com.intellij.psi.search.GlobalSearchScope;
34 import com.intellij.psi.util.PsiTreeUtil;
35 import com.intellij.psi.util.PsiUtil;
36 import com.intellij.refactoring.IntroduceHandlerBase;
37 import com.intellij.refactoring.RefactoringActionHandler;
38 import com.intellij.refactoring.RefactoringBundle;
39 import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
40 import com.intellij.refactoring.rename.RenameJavaVariableProcessor;
41 import com.intellij.refactoring.util.CommonRefactoringUtil;
42 import com.intellij.refactoring.util.EnumConstantsUtil;
43 import com.intellij.refactoring.util.RefactoringUtil;
44 import com.intellij.refactoring.util.occurences.OccurenceManager;
45 import com.intellij.util.IncorrectOperationException;
46 import org.jetbrains.annotations.NonNls;
47 import org.jetbrains.annotations.NotNull;
48 import org.jetbrains.annotations.Nullable;
50 import java.util.ArrayList;
51 import java.util.HashMap;
52 import java.util.List;
54 public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase implements RefactoringActionHandler {
55 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceField.BaseExpressionToFieldHandler");
57 public enum InitializationPlace {
64 private PsiClass myParentClass;
66 protected boolean invokeImpl(final Project project, @NotNull final PsiExpression selectedExpr, final Editor editor) {
67 final PsiElement element = getPhysicalElement(selectedExpr);
69 final PsiFile file = element.getContainingFile();
70 LOG.assertTrue(file != null, "expr.getContainingFile() == null");
72 if (LOG.isDebugEnabled()) {
73 LOG.debug("expression:" + selectedExpr);
76 myParentClass = getParentClass(selectedExpr);
77 if (myParentClass == null) {
78 if (JspPsiUtil.isInJspFile(file)) {
79 CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.message("error.not.supported.for.jsp", getRefactoringName()),
80 getRefactoringName(), getHelpID());
84 LOG.assertTrue(false);
89 if (!validClass(myParentClass, editor)) {
93 PsiType tempType = getTypeByExpression(selectedExpr);
94 if (tempType == null) {
95 String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("unknown.expression.type"));
96 CommonRefactoringUtil.showErrorHint(project, editor, message, getRefactoringName(), getHelpID());
100 if (PsiType.VOID.equals(tempType)) {
101 String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("selected.expression.has.void.type"));
102 CommonRefactoringUtil.showErrorHint(project, editor, message, getRefactoringName(), getHelpID());
107 if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return false;
109 final PsiClass parentClass = myParentClass;
110 final OccurenceManager occurenceManager = createOccurenceManager(selectedExpr, parentClass);
111 final PsiExpression[] occurrences = occurenceManager.getOccurences();
112 final PsiElement anchorStatementIfAll = occurenceManager.getAnchorStatementForAll();
114 List<RangeHighlighter> highlighters = null;
115 if (editor != null) {
116 highlighters = RefactoringUtil.highlightAllOccurences(project, occurrences, editor);
119 PsiElement tempAnchorElement = RefactoringUtil.getParentExpressionAnchorElement(selectedExpr);
121 final Settings settings =
122 showRefactoringDialog(project, editor, myParentClass, selectedExpr, tempType,
123 occurrences, tempAnchorElement, anchorStatementIfAll);
125 if (settings == null) return false;
127 if (settings.getForcedType() != null) {
128 tempType = settings.getForcedType();
130 final PsiType type = tempType;
132 final String fieldName = settings.getFieldName();
133 final PsiElement anchorElementIfOne = tempAnchorElement;
134 final boolean replaceAll = settings.isReplaceAll();
136 tempAnchorElement = anchorStatementIfAll;
138 final PsiElement anchorElement = tempAnchorElement;
141 if (editor != null) {
142 HighlightManager highlightManager = HighlightManager.getInstance(project);
143 for (RangeHighlighter highlighter : highlighters) {
144 highlightManager.removeSegmentHighlighter(editor, highlighter);
148 PsiElement anchor = getNormalizedAnchor(anchorElement);
150 boolean tempDeleteSelf = false;
151 if (element.getParent() instanceof PsiExpressionStatement && anchor.equals(anchorElement)) {
152 PsiStatement statement = (PsiStatement)element.getParent();
153 if (statement.getParent() instanceof PsiCodeBlock) {
154 tempDeleteSelf = true;
157 final boolean deleteSelf = tempDeleteSelf;
159 final Runnable runnable = new Runnable() {
162 PsiExpression expr = selectedExpr;
163 InitializationPlace initializerPlace = settings.getInitializerPlace();
164 final PsiLocalVariable localVariable = settings.getLocalVariable();
165 final boolean deleteLocalVariable = settings.isDeleteLocalVariable();
166 PsiExpression initializer;
167 if (localVariable != null) {
168 initializer = localVariable.getInitializer();
174 final PsiMethod enclosingConstructor = getEnclosingConstructor(myParentClass, anchorElement);
175 final PsiClass destClass = settings.getDestinationClass() == null ? myParentClass : settings.getDestinationClass();
177 if (!CommonRefactoringUtil.checkReadOnlyStatus(project, destClass.getContainingFile())) return;
179 ChangeContextUtil.encodeContextInfo(initializer, true);
180 PsiField field = settings.isIntroduceEnumConstant() ? EnumConstantsUtil.createEnumConstant(destClass, fieldName, initializer) : createField(fieldName, type, initializer, initializerPlace == InitializationPlace.IN_FIELD_DECLARATION && initializer != null);
181 if (!settings.isIntroduceEnumConstant()) {
182 PsiUtil.setModifierProperty(field, settings.getFieldVisibility(), true);
183 if (settings.isDeclareFinal()) {
184 PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true);
186 if (settings.isDeclareStatic()) {
187 PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true);
189 if (settings.isAnnotateAsNonNls()) {
190 PsiAnnotation annotation = JavaPsiFacade.getInstance(myParentClass.getProject()).getElementFactory()
191 .createAnnotationFromText("@" + AnnotationUtil.NON_NLS, myParentClass);
192 field.getModifierList().addAfter(annotation, null);
193 JavaCodeStyleManager.getInstance(myParentClass.getProject()).shortenClassReferences(field.getModifierList());
196 PsiElement finalAnchorElement = null;
197 if (destClass == myParentClass) {
198 for (finalAnchorElement = anchorElement;
199 finalAnchorElement != null && finalAnchorElement.getParent() != destClass;
200 finalAnchorElement = finalAnchorElement.getParent()) {
204 PsiMember anchorMember = finalAnchorElement instanceof PsiMember ? (PsiMember)finalAnchorElement : null;
206 if ((anchorMember instanceof PsiField) &&
207 anchorMember.hasModifierProperty(PsiModifier.STATIC) == field.hasModifierProperty(PsiModifier.STATIC)) {
208 field = (PsiField)destClass.addBefore(field, anchorMember);
210 else if (anchorMember instanceof PsiClassInitializer) {
211 field = (PsiField)destClass.addBefore(field, anchorMember);
212 destClass.addBefore(CodeEditUtil.createLineFeed(field.getManager()), anchorMember);
215 field = (PsiField)destClass.add(field);
217 PsiStatement assignStatement = null;
218 PsiElement anchorElementHere = null;
219 if (initializerPlace == InitializationPlace.IN_CURRENT_METHOD && initializer != null ||
220 initializerPlace == InitializationPlace.IN_CONSTRUCTOR && enclosingConstructor != null && initializer != null) {
222 if (enclosingConstructor != null) {
223 final PsiElement anchorInConstructor = occurenceManager.getAnchorStatementForAllInScope(enclosingConstructor);
224 anchorElementHere = anchorInConstructor != null ? anchorInConstructor : anchorStatementIfAll;
227 anchorElementHere = anchorStatementIfAll;
231 anchorElementHere = anchorElementIfOne;
233 assignStatement = createAssignment(field, initializer, anchorElementHere);
234 if (!IntroduceVariableBase.isLoopOrIf(anchorElementHere.getParent())) {
235 anchorElementHere.getParent().addBefore(assignStatement, getNormalizedAnchor(anchorElementHere));
238 if (initializerPlace == InitializationPlace.IN_CONSTRUCTOR && initializer != null) {
239 addInitializationToConstructors(initializer, field, enclosingConstructor);
241 if (initializerPlace == InitializationPlace.IN_SETUP_METHOD && initializer != null) {
242 addInitializationToSetUp(initializer, field, occurenceManager, replaceAll);
244 if (expr.getParent() instanceof PsiParenthesizedExpression) {
245 expr = (PsiExpression)expr.getParent();
248 element.getParent().delete();
252 List<PsiElement> array = new ArrayList<PsiElement>();
253 for (PsiExpression occurrence : occurrences) {
254 if (occurrence instanceof PsiExpression) {
255 occurrence = RefactoringUtil.outermostParenthesizedExpression(occurrence);
257 if (deleteSelf && occurrence.equals(expr)) continue;
258 final PsiElement replaced = RefactoringUtil.replaceOccurenceWithFieldRef(occurrence, field, destClass);
259 if (replaced != null) {
264 if (editor != null) {
265 if (!ApplicationManager.getApplication().isUnitTestMode()) {
266 PsiElement[] exprsToHighlight = array.toArray(new PsiElement[array.size()]);
267 HighlightManager highlightManager = HighlightManager.getInstance(project);
268 highlightManager.addOccurrenceHighlights(editor, exprsToHighlight, highlightAttributes(), true, null);
269 WindowManager.getInstance().getStatusBar(project).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting"));
275 expr = RefactoringUtil.outermostParenthesizedExpression(expr);
276 RefactoringUtil.replaceOccurenceWithFieldRef(expr, field, destClass);
280 if (anchorElementHere != null && IntroduceVariableBase.isLoopOrIf(anchorElementHere.getParent())) {
281 IntroduceVariableBase.putStatementInLoopBody(assignStatement, anchorElementHere.getParent(), anchorElementHere);
285 if (localVariable != null) {
286 if (deleteLocalVariable) {
287 localVariable.normalizeDeclaration();
288 localVariable.getParent().delete();
292 ChangeContextUtil.clearContextInfo(initializer);
294 catch (IncorrectOperationException e) {
300 CommandProcessor.getInstance().executeCommand(
304 ApplicationManager.getApplication().runWriteAction(runnable);
307 getRefactoringName(), null
313 private static PsiElement getPhysicalElement(final PsiExpression selectedExpr) {
314 PsiElement element = selectedExpr.getUserData(ElementToWorkOn.PARENT);
315 if (element == null) element = selectedExpr;
319 private static TextAttributes highlightAttributes() {
320 return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(
321 EditorColors.SEARCH_RESULT_ATTRIBUTES
325 protected abstract OccurenceManager createOccurenceManager(PsiExpression selectedExpr, PsiClass parentClass);
327 protected final PsiClass getParentClass() {
328 return myParentClass;
331 protected abstract boolean validClass(PsiClass parentClass, Editor editor);
333 protected boolean isStaticField() {
337 private static PsiElement getNormalizedAnchor(PsiElement anchorElement) {
338 PsiElement child = anchorElement;
339 while (child != null) {
340 PsiElement prev = child.getPrevSibling();
341 if (RefactoringUtil.isExpressionAnchorElement(prev)) break;
342 if (prev instanceof PsiJavaToken && ((PsiJavaToken)prev).getTokenType() == JavaTokenType.LBRACE) break;
346 child = PsiTreeUtil.skipSiblingsForward(child, PsiWhiteSpace.class, PsiComment.class);
352 anchor = anchorElement;
357 protected abstract String getHelpID();
359 protected abstract Settings showRefactoringDialog(Project project, Editor editor, PsiClass parentClass, PsiExpression expr,
360 PsiType type, PsiExpression[] occurences, PsiElement anchorElement,
361 PsiElement anchorElementIfAll);
364 private static PsiType getTypeByExpression(PsiExpression expr) {
365 return RefactoringUtil.getTypeByExpressionWithExpectedType(expr);
368 public PsiClass getParentClass(PsiExpression initializerExpression) {
369 PsiElement element = initializerExpression.getUserData(ElementToWorkOn.PARENT);
370 if (element == null) element = initializerExpression.getParent();
371 PsiElement parent = element;
372 while (parent != null) {
373 if (parent instanceof PsiClass && !(parent instanceof PsiAnonymousClass)) {
374 return (PsiClass)parent;
376 parent = parent.getParent();
381 public static PsiMethod getEnclosingConstructor(PsiClass parentClass, PsiElement element) {
382 if (element == null) return null;
383 final PsiMethod[] constructors = parentClass.getConstructors();
384 for (PsiMethod constructor : constructors) {
385 if (PsiTreeUtil.isAncestor(constructor, element, false)) return constructor;
390 private void addInitializationToSetUp(final PsiExpression initializer,
391 final PsiField field,
392 final OccurenceManager occurenceManager, final boolean replaceAll) throws IncorrectOperationException {
393 final PsiMethod setupMethod = TestUtil.findSetUpMethod(myParentClass);
395 assert setupMethod != null;
397 PsiElement anchor = null;
398 if (PsiTreeUtil.isAncestor(setupMethod, initializer, true)) {
400 ? occurenceManager.getAnchorStatementForAllInScope(setupMethod)
401 : PsiTreeUtil.getParentOfType(initializer, PsiStatement.class);
404 final PsiExpressionStatement expressionStatement =
405 (PsiExpressionStatement)JavaPsiFacade.getInstance(myParentClass.getProject()).getElementFactory()
406 .createStatementFromText(field.getName() + "= expr;", null);
407 PsiAssignmentExpression expr = (PsiAssignmentExpression)expressionStatement.getExpression();
408 final PsiExpression rExpression = expr.getRExpression();
409 LOG.assertTrue(rExpression != null);
410 rExpression.replace(initializer);
412 final PsiCodeBlock body = setupMethod.getBody();
414 body.addBefore(expressionStatement, anchor);
417 private void addInitializationToConstructors(PsiExpression initializerExpression, PsiField field, PsiMethod enclosingConstructor) {
419 PsiClass aClass = field.getContainingClass();
420 PsiMethod[] constructors = aClass.getConstructors();
422 boolean added = false;
423 for (PsiMethod constructor : constructors) {
424 if (constructor == enclosingConstructor) continue;
425 PsiCodeBlock body = constructor.getBody();
426 if (body == null) continue;
427 PsiStatement[] statements = body.getStatements();
428 if (statements.length > 0) {
429 PsiStatement first = statements[0];
430 if (first instanceof PsiExpressionStatement) {
431 PsiExpression expression = ((PsiExpressionStatement)first).getExpression();
432 if (expression instanceof PsiMethodCallExpression) {
433 @NonNls String text = ((PsiMethodCallExpression)expression).getMethodExpression().getText();
434 if ("this".equals(text)) {
440 PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild());
441 assignment = (PsiStatement) body.add(assignment);
442 ChangeContextUtil.decodeContextInfo(assignment, field.getContainingClass(),
443 RefactoringUtil.createThisExpression(field.getManager(), null));
446 if (!added && enclosingConstructor == null) {
447 PsiElementFactory factory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory();
448 PsiMethod constructor = (PsiMethod)aClass.add(factory.createConstructor());
449 final PsiCodeBlock body = constructor.getBody();
450 PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild());
451 assignment = (PsiStatement) body.add(assignment);
452 ChangeContextUtil.decodeContextInfo(assignment, field.getContainingClass(),
453 RefactoringUtil.createThisExpression(field.getManager(), null));
456 catch (IncorrectOperationException e) {
461 private PsiField createField(String fieldName, PsiType type, PsiExpression initializerExpr, boolean includeInitializer) {
462 @NonNls StringBuilder pattern = new StringBuilder();
463 pattern.append("private int ");
464 pattern.append(fieldName);
465 if (includeInitializer) {
466 pattern.append("=0");
469 PsiManager psiManager = myParentClass.getManager();
470 PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory();
472 PsiField field = factory.createFieldFromText(pattern.toString(), null);
473 field = (PsiField)CodeStyleManager.getInstance(psiManager.getProject()).reformat(field);
474 field.getTypeElement().replace(factory.createTypeElement(type));
475 if (includeInitializer) {
476 field.getInitializer().replace(initializerExpr);
480 catch (IncorrectOperationException e) {
486 private PsiStatement createAssignment(PsiField field, PsiExpression initializerExpr, PsiElement context) {
488 @NonNls String pattern = "x=0;";
489 PsiManager psiManager = myParentClass.getManager();
490 PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory();
491 PsiExpressionStatement statement = (PsiExpressionStatement)factory.createStatementFromText(pattern, null);
492 statement = (PsiExpressionStatement)CodeStyleManager.getInstance(psiManager.getProject()).reformat(statement);
494 PsiAssignmentExpression expr = (PsiAssignmentExpression)statement.getExpression();
495 final PsiExpression rExpression = expr.getRExpression();
496 LOG.assertTrue(rExpression != null);
497 rExpression.replace(initializerExpr);
498 final PsiReferenceExpression fieldReference = RenameJavaVariableProcessor.createMemberReference(field, context);
499 expr.getLExpression().replace(fieldReference);
503 catch (IncorrectOperationException e) {
510 protected Pass<ElementToWorkOn> getElementProcessor(final Project project, final Editor editor) {
511 return new Pass<ElementToWorkOn>() {
513 public void pass(final ElementToWorkOn elementToWorkOn) {
514 if (elementToWorkOn == null) return;
516 if (elementToWorkOn.getExpression() == null) {
517 final PsiLocalVariable localVariable = elementToWorkOn.getLocalVariable();
518 final boolean result = invokeImpl(project, localVariable, editor);
520 editor.getSelectionModel().removeSelection();
523 else if (invokeImpl(project, elementToWorkOn.getExpression(), editor)) {
524 editor.getSelectionModel().removeSelection();
530 protected abstract String getRefactoringName();
532 public static class Settings {
533 private final String myFieldName;
534 private final PsiType myForcedType;
536 private final boolean myReplaceAll;
537 private final boolean myDeclareStatic;
538 private final boolean myDeclareFinal;
539 private final InitializationPlace myInitializerPlace;
540 @Modifier private final String myVisibility;
541 private final boolean myDeleteLocalVariable;
542 private final TargetDestination myTargetClass;
543 private final boolean myAnnotateAsNonNls;
544 private final boolean myIntroduceEnumConstant;
546 public PsiLocalVariable getLocalVariable() {
547 return myLocalVariable;
550 public boolean isDeleteLocalVariable() {
551 return myDeleteLocalVariable;
554 private final PsiLocalVariable myLocalVariable;
556 public String getFieldName() {
560 public boolean isDeclareStatic() {
561 return myDeclareStatic;
564 public boolean isDeclareFinal() {
565 return myDeclareFinal;
568 public InitializationPlace getInitializerPlace() {
569 return myInitializerPlace;
573 public String getFieldVisibility() {
578 public PsiClass getDestinationClass() {
579 return myTargetClass != null ? myTargetClass.getTargetClass() : null;
582 public PsiType getForcedType() {
586 public boolean isReplaceAll() {
590 public boolean isAnnotateAsNonNls() {
591 return myAnnotateAsNonNls;
594 public boolean isIntroduceEnumConstant() {
595 return myIntroduceEnumConstant;
598 public Settings(String fieldName, boolean replaceAll,
599 boolean declareStatic, boolean declareFinal,
600 InitializationPlace initializerPlace, @Modifier String visibility, PsiLocalVariable localVariableToRemove, PsiType forcedType,
601 boolean deleteLocalVariable,
602 TargetDestination targetDestination,
603 final boolean annotateAsNonNls,
604 final boolean introduceEnumConstant) {
606 myFieldName = fieldName;
607 myReplaceAll = replaceAll;
608 myDeclareStatic = declareStatic;
609 myDeclareFinal = declareFinal;
610 myInitializerPlace = initializerPlace;
611 myVisibility = visibility;
612 myLocalVariable = localVariableToRemove;
613 myDeleteLocalVariable = deleteLocalVariable;
614 myForcedType = forcedType;
615 myTargetClass = targetDestination;
616 myAnnotateAsNonNls = annotateAsNonNls;
617 myIntroduceEnumConstant = introduceEnumConstant;
620 public Settings(String fieldName, boolean replaceAll,
621 boolean declareStatic, boolean declareFinal,
622 InitializationPlace initializerPlace, @Modifier String visibility, PsiLocalVariable localVariableToRemove, PsiType forcedType,
623 boolean deleteLocalVariable,
624 PsiClass targetClass,
625 final boolean annotateAsNonNls,
626 final boolean introduceEnumConstant) {
628 this(fieldName, replaceAll, declareStatic, declareFinal, initializerPlace, visibility, localVariableToRemove, forcedType, deleteLocalVariable, new TargetDestination(targetClass), annotateAsNonNls, introduceEnumConstant);
633 public static class TargetDestination {
634 private final String myQualifiedName;
635 private final Project myProject;
637 private PsiClass myParentClass;
638 private PsiClass myTargetClass;
640 public TargetDestination(String qualifiedName, PsiClass parentClass) {
641 myQualifiedName = qualifiedName;
642 myParentClass = parentClass;
643 myProject = parentClass.getProject();
646 public TargetDestination(@NotNull PsiClass targetClass) {
647 myTargetClass = targetClass;
648 myQualifiedName = targetClass.getQualifiedName();
649 myProject = targetClass.getProject();
653 public PsiClass getTargetClass() {
654 if (myTargetClass != null) return myTargetClass;
655 final String packageName = StringUtil.getPackageName(myQualifiedName);
656 PsiPackage psiPackage = JavaPsiFacade.getInstance(myProject).findPackage(packageName);
657 final PsiDirectory psiDirectory;
658 if (psiPackage != null) {
659 final PsiDirectory[] directories = psiPackage.getDirectories(GlobalSearchScope.allScope(myProject));
660 psiDirectory = directories.length > 1 ? DirectoryChooserUtil.chooseDirectory(directories, null, myProject, new HashMap<PsiDirectory, String>()) : directories[0];
662 psiDirectory = PackageUtil.findOrCreateDirectoryForPackage(myProject, packageName, myParentClass.getContainingFile().getContainingDirectory(), false);
664 final String shortName = StringUtil.getShortName(myQualifiedName);
665 myTargetClass = psiDirectory != null ? JavaDirectoryService.getInstance().createClass(psiDirectory, shortName) : null;
666 return myTargetClass;