private void fixReferencesToStatic(GroovyPsiElement classMember, Set<PsiMember> movedMembers)
      throws IncorrectOperationException {
    final StaticReferencesCollector collector = new StaticReferencesCollector(movedMembers);
    classMember.accept(collector);
    ArrayList<GrReferenceElement> refs = collector.getReferences();
    ArrayList<PsiElement> members = collector.getReferees();
    ArrayList<PsiClass> classes = collector.getRefereeClasses();
    GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myProject);

    for (int i = 0; i < refs.size(); i++) {
      GrReferenceElement ref = refs.get(i);
      PsiElement namedElement = members.get(i);
      PsiClass aClass = classes.get(i);

      if (namedElement instanceof PsiNamedElement) {
        GrReferenceExpression newRef =
            (GrReferenceExpression)
                factory.createExpressionFromText(
                    "a." + ((PsiNamedElement) namedElement).getName(), null);
        GrExpression qualifier = newRef.getQualifierExpression();
        assert qualifier != null;
        qualifier =
            (GrExpression)
                qualifier.replace(
                    factory.createReferenceExpressionFromText(aClass.getQualifiedName()));
        qualifier.putCopyableUserData(PRESERVE_QUALIFIER, ref.isQualified());
        PsiElement replaced = ref.replace(newRef);
        JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(replaced);
      }
    }
  }
 private static void genForPart(
     StringBuilder builder, GroovyPsiElement part, final Generator visitor) {
   part.accept(visitor);
   for (String statement : visitor.getContext().myStatements) {
     builder.append(statement).append(", ");
   }
   builder.append(visitor.getBuilder());
 }
 @Override
 public void visitParenthesizedExpression(GrParenthesizedExpression expression) {
   final PsiElement parent = expression.getParent();
   if (parent instanceof GroovyPsiElement) {
     ((GroovyPsiElement) parent).accept(this);
   } else {
     parent.accept(new GroovyPsiElementVisitor(this));
   }
 }
  @Override
  public void processDynamicElements(
      final @NotNull PsiType qualifierType,
      final PsiScopeProcessor processor,
      final GroovyPsiElement place,
      final ResolveState state) {
    if (!GroovyPsiManager.isInheritorCached(qualifierType, CommonClassNames.JAVA_UTIL_COLLECTION))
      return;

    final PsiType collectionType = PsiUtil.extractIterableTypeParameter(qualifierType, true);
    if (collectionType == null) return;

    final PsiScopeProcessor fieldSearcher =
        new FieldSearcher(
            processor,
            JavaPsiFacade.getInstance(place.getProject())
                .findClass(CommonClassNames.JAVA_UTIL_COLLECTION, place.getResolveScope()));
    ResolveUtil.processAllDeclarations(collectionType, fieldSearcher, state, place);
  }
  @Override
  public void processDynamicElements(
      @NotNull PsiType qualifierType,
      PsiClass aClass,
      PsiScopeProcessor processor,
      GroovyPsiElement place,
      ResolveState state) {
    ClassHint classHint = processor.getHint(ClassHint.KEY);
    if (classHint != null && !classHint.shouldProcess(ClassHint.ResolveKind.PROPERTY)) return;

    String nameHint = ResolveUtil.getNameHint(processor);

    Map<String, PsiClass> supers = TypesUtil.getSuperClassesWithCache(aClass);

    PsiElement grCall = place.getParent();
    if (grCall instanceof GrMethodCall) {
      PsiElement grClosure = grCall.getParent();
      if (grClosure instanceof GrClosableBlock) {
        PsiElement contentField = grClosure.getParent();
        if (contentField instanceof GrField) {
          GrField f = (GrField) contentField;
          if ("content".equals(f.getName())
              && f.hasModifierProperty(PsiModifier.STATIC)
              && f.getContainingClass() == aClass) {
            Map<String, PsiField> elements = GebUtil.getContentElements(aClass);
            for (PsiField field : elements.values()) {
              if (field.getNavigationElement() == place) {
                return; // Don't resolve variable definition.
              }
            }
          }
        }
      }
    }

    for (PsiClass psiClass : supers.values()) {
      Map<String, PsiField> contentFields = GebUtil.getContentElements(psiClass);

      if (nameHint == null) {
        for (Map.Entry<String, PsiField> entry : contentFields.entrySet()) {
          if (!processor.execute(entry.getValue(), state)) return;
        }
      } else {
        PsiField field = contentFields.get(nameHint);
        if (field != null) {
          processor.execute(field, state);
          return;
        }
      }
    }
  }
  public static void detectAccessibilityConflicts(
      @Nullable GroovyPsiElement elementToProcess,
      final UsageInfo[] usages,
      MultiMap<PsiElement, String> conflicts,
      boolean replaceFieldsWithGetters,
      Project project) {
    if (elementToProcess == null) return;

    final ReferencedElementsCollector collector = new ReferencedElementsCollector();
    elementToProcess.accept(collector);
    final List<PsiElement> result = collector.getResult();
    if (result.isEmpty()) return;

    for (final UsageInfo usageInfo : usages) {
      if (!(usageInfo instanceof ExternalUsageInfo)
          || !IntroduceParameterUtil.isMethodUsage(usageInfo)) continue;

      final PsiElement place = usageInfo.getElement();
      for (PsiElement element : result) {
        if (element instanceof PsiField && replaceFieldsWithGetters) {
          // check getter access instead
          final PsiClass psiClass = ((PsiField) element).getContainingClass();
          LOG.assertTrue(psiClass != null);
          final PsiMethod method = GroovyPropertyUtils.findGetterForField((PsiField) element);
          if (method != null) {
            element = method;
          }
        }
        if (element instanceof PsiMember
            && !JavaPsiFacade.getInstance(project)
                .getResolveHelper()
                .isAccessible((PsiMember) element, place, null)) {
          String message =
              RefactoringBundle.message(
                  "0.is.not.accessible.from.1.value.for.introduced.parameter.in.that.method.call.will.be.incorrect",
                  RefactoringUIUtil.getDescription(element, true),
                  RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(place), true));
          conflicts.putValue(element, message);
        }
      }
    }
  }
  private void buildFlowForClosure(final GrClosableBlock closure) {
    for (GrParameter parameter : closure.getAllParameters()) {
      if (myPolicy.isVariableInitialized(parameter)) {
        addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, WRITE));
      }
    }

    addNode(new ReadWriteVariableInstruction("owner", closure.getLBrace(), WRITE));

    PsiElement child = closure.getFirstChild();
    while (child != null) {
      if (child instanceof GroovyPsiElement) {
        ((GroovyPsiElement) child).accept(this);
      }
      child = child.getNextSibling();
    }

    final GrStatement[] statements = closure.getStatements();
    if (statements.length > 0) {
      handlePossibleReturn(statements[statements.length - 1]);
    }
  }
  public Instruction[] buildControlFlow(GroovyPsiElement scope) {
    myInstructions = new ArrayList<InstructionImpl>();
    myProcessingStack = new ArrayDeque<InstructionImpl>();
    myCaughtExceptionInfos = new ArrayDeque<ExceptionInfo>();
    myConditions = new ArrayDeque<ConditionInstruction>();

    myFinallyCount = 0;
    myPending = new ArrayList<Pair<InstructionImpl, GroovyPsiElement>>();
    myInstructionNumber = 0;

    myScope = scope;

    startNode(null);
    if (scope instanceof GrClosableBlock) {
      buildFlowForClosure((GrClosableBlock) scope);
    } else {
      scope.accept(this);
    }

    final InstructionImpl end = startNode(null);
    checkPending(end); // collect return edges

    return assertValidPsi(myInstructions.toArray(new Instruction[myInstructions.size()]));
  }
  public static MultiMap<PsiElement, String> checkConflicts(
      final MemberInfoBase<? extends GrMember>[] infos,
      @NotNull final PsiClass subclass,
      @Nullable PsiClass superClass,
      @NotNull final PsiPackage targetPackage,
      @NotNull PsiDirectory targetDirectory,
      final InterfaceContainmentVerifier interfaceContainmentVerifier,
      boolean movedMembers2Super) {
    final PsiElement targetRepresentativeElement;
    final boolean isInterfaceTarget;
    if (superClass != null) {
      isInterfaceTarget = superClass.isInterface();
      targetRepresentativeElement = superClass;
    } else {
      isInterfaceTarget = false;
      targetRepresentativeElement = targetDirectory;
    }

    final Set<GrMember> movedMembers = ContainerUtil.newHashSet();
    final Set<GrMethod> abstractMethods = ContainerUtil.newHashSet();
    for (MemberInfoBase<? extends GrMember> info : infos) {
      GrMember member = info.getMember();
      if (member instanceof GrMethod) {
        if (!info.isToAbstract() && !isInterfaceTarget) {
          movedMembers.add(member);
        } else {
          abstractMethods.add((GrMethod) member);
        }
      } else {
        movedMembers.add(member);
      }
    }

    final Set<PsiMethod> allAbstractMethods = new HashSet<PsiMethod>(abstractMethods);
    if (superClass != null) {
      for (PsiMethod method : subclass.getMethods()) {
        if (!movedMembers.contains(method) && !method.hasModifierProperty(PsiModifier.PRIVATE)) {
          if (method.findSuperMethods(superClass).length > 0) {
            allAbstractMethods.add(method);
          }
        }
      }
    }

    final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();

    GrRefactoringConflictsUtil.analyzeAccessibilityConflicts(
        movedMembers,
        superClass,
        conflicts,
        VisibilityUtil.ESCALATE_VISIBILITY,
        targetRepresentativeElement,
        allAbstractMethods);

    if (superClass != null) {
      if (movedMembers2Super) {
        checkSuperclassMembers(superClass, infos, conflicts);
        if (isInterfaceTarget) {
          checkInterfaceTarget(infos, conflicts);
        }
      } else {
        final String qualifiedName = superClass.getQualifiedName();
        assert qualifiedName != null;
        if (superClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
          if (!Comparing.strEqual(
              StringUtil.getPackageName(qualifiedName), targetPackage.getQualifiedName())) {
            conflicts.putValue(
                superClass,
                RefactoringUIUtil.getDescription(superClass, true)
                    + " won't be accessible from "
                    + RefactoringUIUtil.getDescription(targetPackage, true));
          }
        }
      }
    }
    // check if moved methods use other members in the classes between Subclass and Superclass
    List<PsiElement> checkModuleConflictsList = new ArrayList<PsiElement>();
    for (PsiMember member : movedMembers) {
      if (member instanceof PsiMethod
          || member instanceof PsiClass && !(member instanceof PsiCompiledElement)) {
        GrClassMemberReferenceVisitor visitor =
            movedMembers2Super
                ? new ConflictingUsagesOfSubClassMembers(
                    member,
                    movedMembers,
                    abstractMethods,
                    subclass,
                    superClass,
                    superClass != null ? null : targetPackage,
                    conflicts,
                    interfaceContainmentVerifier)
                : new ConflictingUsagesOfSuperClassMembers(
                    member, subclass, targetPackage, movedMembers, conflicts);
        ((GroovyPsiElement) member).accept(visitor);
      }
      checkModuleConflictsList.add(member);
    }
    for (final PsiMethod method : abstractMethods) {
      ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getParameterList());
      ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getReturnTypeElement());
      ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getTypeParameterList());
    }
    GrRefactoringConflictsUtil.analyzeModuleConflicts(
        subclass.getProject(),
        checkModuleConflictsList,
        new UsageInfo[0],
        targetRepresentativeElement,
        conflicts);
    final String fqName = subclass.getQualifiedName();
    final String packageName;
    if (fqName != null) {
      packageName = StringUtil.getPackageName(fqName);
    } else {
      final PsiFile psiFile = PsiTreeUtil.getParentOfType(subclass, PsiFile.class);
      if (psiFile instanceof PsiClassOwner) {
        packageName = ((PsiClassOwner) psiFile).getPackageName();
      } else {
        packageName = null;
      }
    }
    final boolean toDifferentPackage =
        !Comparing.strEqual(targetPackage.getQualifiedName(), packageName);
    for (final GrMethod abstractMethod : abstractMethods) {
      abstractMethod.accept(
          new GrClassMemberReferenceVisitor(subclass) {
            @Override
            protected void visitClassMemberReferenceElement(
                GrMember classMember, GrReferenceElement classMemberReference) {
              if (classMember != null && willBeMoved(classMember, movedMembers)) {
                boolean isAccessible = false;
                if (classMember.hasModifierProperty(PsiModifier.PRIVATE)) {
                  isAccessible = true;
                } else if (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)
                    && toDifferentPackage) {
                  isAccessible = true;
                }
                if (isAccessible) {
                  String message =
                      RefactoringUIUtil.getDescription(abstractMethod, false)
                          + " uses "
                          + RefactoringUIUtil.getDescription(classMember, true)
                          + " which won't be accessible from the subclass.";
                  message = CommonRefactoringUtil.capitalize(message);
                  conflicts.putValue(classMember, message);
                }
              }
            }
          });
      if (abstractMethod.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && toDifferentPackage) {
        if (!isInterfaceTarget) {
          String message =
              "Can't make "
                  + RefactoringUIUtil.getDescription(abstractMethod, false)
                  + " abstract as it won't be accessible from the subclass.";
          message = CommonRefactoringUtil.capitalize(message);
          conflicts.putValue(abstractMethod, message);
        }
      }
    }
    return conflicts;
  }
예제 #10
0
  public void moveMembersToBase() throws IncorrectOperationException {
    final HashSet<PsiMember> movedMembers = ContainerUtil.newHashSet();
    myMembersAfterMove = ContainerUtil.newHashSet();

    // build aux sets
    for (GrMemberInfo info : myMembersToMove) {
      movedMembers.add(info.getMember());
    }

    // correct private member visibility
    for (GrMemberInfo info : myMembersToMove) {
      if (info.getMember() instanceof PsiClass && info.getOverrides() != null) continue;
      setCorrectVisibility(movedMembers, info);
      GroovyChangeContextUtil.encodeContextInfo(info.getMember());
      info.getMember().accept(new QualifiedThisSuperSearcher());
      fixReferencesToStatic(info.getMember(), movedMembers);
    }

    final PsiSubstitutor substitutor = upDownSuperClassSubstitutor();

    // do actual move
    for (GrMemberInfo info : myMembersToMove) {
      if (info.getMember() instanceof PsiMethod) {
        doMoveMethod(substitutor, info);
      } else if (info.getMember() instanceof GrField) {
        doMoveField(substitutor, info);
      } else if (info.getMember() instanceof PsiClass) {
        doMoveClass(substitutor, info);
      }
    }

    ExplicitSuperDeleter explicitSuperDeleter = new ExplicitSuperDeleter();
    for (PsiMember member : myMembersAfterMove) {
      ((GrMember) member).accept(explicitSuperDeleter);
    }
    explicitSuperDeleter.fixSupers();

    final QualifiedThisSuperAdjuster qualifiedThisSuperAdjuster = new QualifiedThisSuperAdjuster();
    for (PsiMember member : myMembersAfterMove) {
      ((GrMember) member).accept(qualifiedThisSuperAdjuster);
    }

    for (PsiMember member : myMembersAfterMove) {
      GroovyChangeContextUtil.decodeContextInfo(member, null, null);
    }

    final JavaRefactoringListenerManagerImpl listenerManager =
        (JavaRefactoringListenerManagerImpl) JavaRefactoringListenerManager.getInstance(myProject);
    for (final PsiMember movedMember : myMembersAfterMove) {
      ((GroovyPsiElement) movedMember)
          .accept(
              new GroovyRecursiveElementVisitor() {
                @Override
                public void visitReferenceExpression(GrReferenceExpression referenceExpression) {
                  if (processRef(referenceExpression)) return;
                  super.visitReferenceExpression(referenceExpression);
                }

                @Override
                public void visitCodeReferenceElement(GrCodeReferenceElement refElement) {
                  if (processRef(refElement)) return;
                  super.visitCodeReferenceElement(refElement);
                }

                private boolean processRef(
                    @NotNull GrReferenceElement<? extends GroovyPsiElement> refElement) {
                  final PsiElement qualifier = refElement.getQualifier();
                  if (qualifier != null) {
                    final Boolean preserveQualifier =
                        qualifier.getCopyableUserData(PRESERVE_QUALIFIER);
                    if (preserveQualifier != null && !preserveQualifier) {
                      refElement.setQualifier(null);
                      return true;
                    }
                  }
                  return false;
                }
              });
      listenerManager.fireMemberMoved(mySourceClass, movedMember);
    }
  }
 private void acceptNullable(@Nullable GroovyPsiElement element) {
   if (element != null) {
     element.accept(this);
   }
 }
  private void error(String descr) {
    PsiFile file = myScope.getContainingFile();
    String fileText = file != null ? file.getText() : null;

    LogMessageEx.error(LOG, descr, myScope.getText(), "\n------------------\n", fileText);
  }