Package org.aspectj.org.eclipse.jdt.internal.core.hierarchy

Source Code of org.aspectj.org.eclipse.jdt.internal.core.hierarchy.ChangeCollector

/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core.hierarchy;

import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import org.aspectj.org.eclipse.jdt.core.*;
import org.aspectj.org.eclipse.jdt.core.IJavaElementDelta;
import org.aspectj.org.eclipse.jdt.core.IType;
import org.aspectj.org.eclipse.jdt.core.JavaModelException;
import org.aspectj.org.eclipse.jdt.internal.core.JavaElement;
import org.aspectj.org.eclipse.jdt.internal.core.SimpleDelta;

/*
* Collects changes (reported through fine-grained deltas) that can affect a type hierarchy.
*/
public class ChangeCollector {
 
  /*
   * A table from ITypes to TypeDeltas
   */
  HashMap changes = new HashMap();
 
  TypeHierarchy hierarchy;
 
  public ChangeCollector(TypeHierarchy hierarchy) {
    this.hierarchy = hierarchy;
  }
 
  /*
   * Adds the children of the given delta to the list of changes.
   */
  private void addAffectedChildren(IJavaElementDelta delta) throws JavaModelException {
    IJavaElementDelta[] children = delta.getAffectedChildren();
    for (int i = 0, length = children.length; i < length; i++) {
      IJavaElementDelta child = children[i];
      IJavaElement childElement = child.getElement();
      switch (childElement.getElementType()) {
        case IJavaElement.IMPORT_CONTAINER:
          addChange((IImportContainer)childElement, child);
          break;
        case IJavaElement.IMPORT_DECLARATION:
          addChange((IImportDeclaration)childElement, child);
          break;
        case IJavaElement.TYPE:
          addChange((IType)childElement, child);
          break;
        case IJavaElement.INITIALIZER:
        case IJavaElement.FIELD:
        case IJavaElement.METHOD:
          addChange((IMember)childElement, child);
          break;
      }
    }
  }
 
  /*
   * Adds the given delta on a compilation unit to the list of changes.
   */
  public void addChange(ICompilationUnit cu, IJavaElementDelta newDelta) throws JavaModelException {
    int newKind = newDelta.getKind();
    switch (newKind) {
      case IJavaElementDelta.ADDED:
        ArrayList allTypes = new ArrayList();
        getAllTypesFromElement(cu, allTypes);
        for (int i = 0, length = allTypes.size(); i < length; i++) {
          IType type = (IType)allTypes.get(i);
          addTypeAddition(type, (SimpleDelta)this.changes.get(type));
        }
        break;
      case IJavaElementDelta.REMOVED:
        allTypes = new ArrayList();
        getAllTypesFromHierarchy((JavaElement)cu, allTypes);
        for (int i = 0, length = allTypes.size(); i < length; i++) {
          IType type = (IType)allTypes.get(i);
          addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
        }
        break;
      case IJavaElementDelta.CHANGED:
        addAffectedChildren(newDelta);
        break;
    }
  }
 
  private void addChange(IImportContainer importContainer, IJavaElementDelta newDelta) throws JavaModelException {
    int newKind = newDelta.getKind();
    if (newKind == IJavaElementDelta.CHANGED) {
      addAffectedChildren(newDelta);
      return;
    }
    SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importContainer);
    if (existingDelta != null) {
      switch (newKind) {
        case IJavaElementDelta.ADDED:
          if (existingDelta.getKind() == IJavaElementDelta.REMOVED) {
            // REMOVED then ADDED
            this.changes.remove(importContainer);
          }
          break;
        case IJavaElementDelta.REMOVED:
          if (existingDelta.getKind() == IJavaElementDelta.ADDED) {
            // ADDED then REMOVED
            this.changes.remove(importContainer);
          }
          break;
          // CHANGED handled above
      }
    } else {
      SimpleDelta delta = new SimpleDelta();
      switch (newKind) {
        case IJavaElementDelta.ADDED:
          delta.added();
          break;
        case IJavaElementDelta.REMOVED:
          delta.removed();
          break;
      }
      this.changes.put(importContainer, delta);
    }
  }

  private void addChange(IImportDeclaration importDecl, IJavaElementDelta newDelta) {
    SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importDecl);
    int newKind = newDelta.getKind();
    if (existingDelta != null) {
      switch (newKind) {
        case IJavaElementDelta.ADDED:
          if (existingDelta.getKind() == IJavaElementDelta.REMOVED) {
            // REMOVED then ADDED
            this.changes.remove(importDecl);
          }
          break;
        case IJavaElementDelta.REMOVED:
          if (existingDelta.getKind() == IJavaElementDelta.ADDED) {
            // ADDED then REMOVED
            this.changes.remove(importDecl);
          }
          break;
        // CHANGED cannot happen for import declaration
      }
    } else {
      SimpleDelta delta = new SimpleDelta();
      switch (newKind) {
        case IJavaElementDelta.ADDED:
          delta.added();
          break;
        case IJavaElementDelta.REMOVED:
          delta.removed();
          break;
      }
      this.changes.put(importDecl, delta);
    }
  }
 
  /*
   * Adds a change for the given member (a method, a field or an initializer) and the types it defines.
   */
  private void addChange(IMember member, IJavaElementDelta newDelta) throws JavaModelException {
    int newKind = newDelta.getKind();
    switch (newKind) {
      case IJavaElementDelta.ADDED:
        ArrayList allTypes = new ArrayList();
        getAllTypesFromElement(member, allTypes);
        for (int i = 0, length = allTypes.size(); i < length; i++) {
          IType innerType = (IType)allTypes.get(i);
          addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
        }
        break;
      case IJavaElementDelta.REMOVED:
        allTypes = new ArrayList();
        getAllTypesFromHierarchy((JavaElement)member, allTypes);
        for (int i = 0, length = allTypes.size(); i < length; i++) {
          IType type = (IType)allTypes.get(i);
          addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
        }
        break;
      case IJavaElementDelta.CHANGED:
        addAffectedChildren(newDelta);
        break;
    }
  }
 
  /*
   * Adds a change for the given type and the types it defines.
   */
  private void addChange(IType type, IJavaElementDelta newDelta) throws JavaModelException {
     int newKind = newDelta.getKind();
    SimpleDelta existingDelta = (SimpleDelta)this.changes.get(type);
    switch (newKind) {
      case IJavaElementDelta.ADDED:
        addTypeAddition(type, existingDelta);
        ArrayList allTypes = new ArrayList();
        getAllTypesFromElement(type, allTypes);
        for (int i = 0, length = allTypes.size(); i < length; i++) {
          IType innerType = (IType)allTypes.get(i);
          addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
        }
        break;
      case IJavaElementDelta.REMOVED:
        addTypeRemoval(type, existingDelta);
        allTypes = new ArrayList();
        getAllTypesFromHierarchy((JavaElement)type, allTypes);
        for (int i = 0, length = allTypes.size(); i < length; i++) {
          IType innerType = (IType)allTypes.get(i);
          addTypeRemoval(innerType, (SimpleDelta)this.changes.get(innerType));
        }
        break;
      case IJavaElementDelta.CHANGED:
        addTypeChange(type, newDelta.getFlags(), existingDelta);
        addAffectedChildren(newDelta);
        break;
    }
  }

  private void addTypeAddition(IType type, SimpleDelta existingDelta) throws JavaModelException {
    if (existingDelta != null) {
      switch (existingDelta.getKind()) {
        case IJavaElementDelta.REMOVED:
          // REMOVED then ADDED
          boolean hasChange = false;
          if (hasSuperTypeChange(type)) {
            existingDelta.superTypes();
            hasChange = true;
          }
          if (hasVisibilityChange(type)) {
            existingDelta.modifiers();
            hasChange = true;
          }
          if (!hasChange) {
            this.changes.remove(type);
          }
          break;
          // CHANGED then ADDED
          // or ADDED then ADDED: should not happen
      }
    } else {
      // check whether the type addition affects the hierarchy
      String typeName = type.getElementName();
      if (this.hierarchy.hasSupertype(typeName)
          || this.hierarchy.subtypesIncludeSupertypeOf(type)
          || this.hierarchy.missingTypes.contains(typeName)) {
        SimpleDelta delta = new SimpleDelta();
        delta.added();
        this.changes.put(type, delta);
      }
    }
  }
 
  private void addTypeChange(IType type, int newFlags, SimpleDelta existingDelta) throws JavaModelException {
    if (existingDelta != null) {
      switch (existingDelta.getKind()) {
        case IJavaElementDelta.CHANGED:
          // CHANGED then CHANGED
          int existingFlags = existingDelta.getFlags();
          boolean hasChange = false;
          if ((existingFlags & IJavaElementDelta.F_SUPER_TYPES) != 0
              && hasSuperTypeChange(type)) {
            existingDelta.superTypes();
            hasChange = true;
          }
          if ((existingFlags & IJavaElementDelta.F_MODIFIERS) != 0
              && hasVisibilityChange(type)) {
            existingDelta.modifiers();
            hasChange = true;
          }
          if (!hasChange) {
            // super types and visibility are back to the ones in the existing hierarchy
            this.changes.remove(type);
          }
          break;
          // ADDED then CHANGED: leave it as ADDED
          // REMOVED then CHANGED: should not happen
      }
    } else {
      // check whether the type change affects the hierarchy
      SimpleDelta typeDelta = null;
      if ((newFlags & IJavaElementDelta.F_SUPER_TYPES) != 0
          && this.hierarchy.includesTypeOrSupertype(type)) {
        typeDelta = new SimpleDelta();
        typeDelta.superTypes();
      }
      if ((newFlags & IJavaElementDelta.F_MODIFIERS) != 0
          && (this.hierarchy.hasSupertype(type.getElementName())
            || type.equals(this.hierarchy.focusType))) {
        if (typeDelta == null) {
          typeDelta = new SimpleDelta();
        }
        typeDelta.modifiers();
      }
      if (typeDelta != null) {
        this.changes.put(type, typeDelta);
      }
    }
  }

  private void addTypeRemoval(IType type, SimpleDelta existingDelta) {
    if (existingDelta != null) {
      switch (existingDelta.getKind()) {
        case IJavaElementDelta.ADDED:
          // ADDED then REMOVED
          this.changes.remove(type);
          break;
        case IJavaElementDelta.CHANGED:
          // CHANGED then REMOVED
          existingDelta.removed();
          break;
          // REMOVED then REMOVED: should not happen
      }
    } else {
      // check whether the type removal affects the hierarchy
      if (this.hierarchy.contains(type)) {
        SimpleDelta typeDelta = new SimpleDelta();
        typeDelta.removed();
        this.changes.put(type, typeDelta);
      }
    }
  }
 
  /*
   * Returns all types defined in the given element excluding the given element.
   */
  private void getAllTypesFromElement(IJavaElement element, ArrayList allTypes) throws JavaModelException {
    switch (element.getElementType()) {
      case IJavaElement.COMPILATION_UNIT:
        IType[] types = ((ICompilationUnit)element).getTypes();
        for (int i = 0, length = types.length; i < length; i++) {
          IType type = types[i];
          allTypes.add(type);
          getAllTypesFromElement(type, allTypes);
        }
        break;
      case IJavaElement.TYPE:
        types = ((IType)element).getTypes();
        for (int i = 0, length = types.length; i < length; i++) {
          IType type = types[i];
          allTypes.add(type);
          getAllTypesFromElement(type, allTypes);
        }
        break;
      case IJavaElement.INITIALIZER:
      case IJavaElement.FIELD:
      case IJavaElement.METHOD:
        IJavaElement[] children = ((IMember)element).getChildren();
        for (int i = 0, length = children.length; i < length; i++) {
          IType type = (IType)children[i];
          allTypes.add(type);
          getAllTypesFromElement(type, allTypes);
        }
        break;
    }
  }
 
  /*
   * Returns all types in the existing hierarchy that have the given element as a parent.
   */
  private void getAllTypesFromHierarchy(JavaElement element, ArrayList allTypes) {
    switch (element.getElementType()) {
      case IJavaElement.COMPILATION_UNIT:
        ArrayList types = (ArrayList)this.hierarchy.files.get(element);
        if (types != null) {
          allTypes.addAll(types);
        }
        break;
      case IJavaElement.TYPE:
      case IJavaElement.INITIALIZER:
      case IJavaElement.FIELD:
      case IJavaElement.METHOD:
        types = (ArrayList)this.hierarchy.files.get(((IMember)element).getCompilationUnit());
        if (types != null) {
          for (int i = 0, length = types.size(); i < length; i++) {
            IType type = (IType)types.get(i);
            if (element.isAncestorOf(type)) {
              allTypes.add(type);
            }
          }
        }
        break;
    }
  }
 
  private boolean hasSuperTypeChange(IType type) throws JavaModelException {
    // check super class
    IType superclass = this.hierarchy.getSuperclass(type);
    String existingSuperclassName = superclass == null ? null : superclass.getElementName();
    String newSuperclassName = type.getSuperclassName();
    if (existingSuperclassName != null && !existingSuperclassName.equals(newSuperclassName)) {
      return true;
    }
   
    // check super interfaces
    IType[] existingSuperInterfaces = this.hierarchy.getSuperInterfaces(type);
    String[] newSuperInterfaces = type.getSuperInterfaceNames();
    if (existingSuperInterfaces.length != newSuperInterfaces.length) {
      return true;
    }
    for (int i = 0, length = newSuperInterfaces.length; i < length; i++) {
      String superInterfaceName = newSuperInterfaces[i];
      if (!superInterfaceName.equals(newSuperInterfaces[i])) {
        return true;
      }
    }
   
    return false;
  }
 
  private boolean hasVisibilityChange(IType type) throws JavaModelException {
    int existingFlags = this.hierarchy.getCachedFlags(type);
    int newFlags = type.getFlags();
    return existingFlags != newFlags;
  }

  /*
   * Whether the hierarchy needs refresh according to the changes collected so far.
   */
  public boolean needsRefresh() {
    return changes.size() != 0;
  }
 
  public String toString() {
    StringBuffer buffer = new StringBuffer();
    Iterator iterator = this.changes.entrySet().iterator();
    while (iterator.hasNext()) {
      Map.Entry entry = (Map.Entry)iterator.next();
      buffer.append(((JavaElement)entry.getKey()).toDebugString());
      buffer.append(entry.getValue());
      if (iterator.hasNext()) {
        buffer.append('\n');
      }
    }
    return buffer.toString();
  }
}
TOP

Related Classes of org.aspectj.org.eclipse.jdt.internal.core.hierarchy.ChangeCollector

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.