/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
package org.eclipse.jdt.internal.debug.core.hcr; | |
import java.util.ArrayList; | |
import org.eclipse.jdt.internal.compiler.parser.InvalidInputException; | |
import org.eclipse.jdt.internal.compiler.parser.Scanner; | |
import org.eclipse.jdt.internal.compiler.parser.TerminalSymbols; | |
import org.eclipse.jdt.internal.core.JavaElement; | |
/** | |
* Comparable Java elements are represented as JavaNodes. | |
*/ | |
class JavaNode { | |
public static final int CU= 0; | |
public static final int PACKAGE= 1; | |
public static final int IMPORT_CONTAINER= 2; | |
public static final int IMPORT= 3; | |
public static final int INTERFACE= 4; | |
public static final int CLASS= 5; | |
public static final int FIELD= 6; | |
public static final int INIT= 7; | |
public static final int CONSTRUCTOR= 8; | |
public static final int METHOD= 9; | |
private String fID; | |
private int fTypeCode; | |
private char[] fBuffer; | |
private int fStart; | |
private int fLength; | |
private ArrayList fChildren; | |
private int fInitializerCount= 1; | |
/** | |
* Creates a new <code>JavaNode</code> for the given range within the specified | |
* buffer. The <code>typeCode</code> is uninterpreted client data. The ID is used when comparing | |
* two nodes with each other: i.e. the differencing engine performs a content compare | |
* on two nodes if their IDs are equal. | |
* | |
* @param typeCode a type code for this node | |
* @param id an identifier for this node | |
* @param buffer buffer on which this node is based on | |
* @param start start position of range within document | |
* @param length length of range | |
*/ | |
JavaNode(int typeCode, String id, char[] buffer, int start, int length) { | |
fTypeCode= typeCode; | |
fID= id; | |
fBuffer= buffer; | |
fStart= start; | |
fLength= length; | |
} | |
/** | |
* Creates a JavaNode under the given parent. | |
* @param type the Java elements type. Legal values are from the range CU to METHOD of this class. | |
* @param name the name of the Java element | |
* @param start the starting position of the java element in the underlying document | |
* @param length the number of characters of the java element in the underlying document | |
*/ | |
JavaNode(JavaNode parent, int type, String name, int start, int length) { | |
this(type, buildID(type, name), parent.fBuffer, start, length); | |
if (parent != null) | |
parent.addChild(this); | |
} | |
/** | |
* Creates a JavaNode for a CU. It represents the root of a | |
* JavaNode tree, so its parent is null. | |
* @param document the document which contains the Java element | |
*/ | |
JavaNode(char[] buffer) { | |
this(CU, buildID(CU, "root"), buffer, 0, buffer.length); //$NON-NLS-1$ | |
} | |
/** | |
* Returns a name which identifies the given typed name. | |
* The type is encoded as a single character at the beginning of the string. | |
*/ | |
private static String buildID(int type, String name) { | |
StringBuffer sb= new StringBuffer(); | |
switch (type) { | |
case JavaNode.CU: | |
sb.append(JavaElement.JEM_COMPILATIONUNIT); | |
break; | |
case JavaNode.CLASS: | |
case JavaNode.INTERFACE: | |
sb.append(JavaElement.JEM_TYPE); | |
sb.append(name); | |
break; | |
case JavaNode.FIELD: | |
sb.append(JavaElement.JEM_FIELD); | |
sb.append(name); | |
break; | |
case JavaNode.CONSTRUCTOR: | |
case JavaNode.METHOD: | |
sb.append(JavaElement.JEM_METHOD); | |
sb.append(name); | |
break; | |
case JavaNode.INIT: | |
sb.append(JavaElement.JEM_INITIALIZER); | |
sb.append(name); | |
break; | |
case JavaNode.PACKAGE: | |
sb.append(JavaElement.JEM_PACKAGEDECLARATION); | |
break; | |
case JavaNode.IMPORT: | |
sb.append(JavaElement.JEM_IMPORTDECLARATION); | |
sb.append(name); | |
break; | |
case JavaNode.IMPORT_CONTAINER: | |
sb.append('<'); | |
break; | |
default: | |
//Assert.isTrue(false); | |
break; | |
} | |
return sb.toString(); | |
} | |
public String getInitializerCount() { | |
return Integer.toString(fInitializerCount++); | |
} | |
public int getStart() { | |
return fStart; | |
} | |
/** | |
* Returns the type code of this node. | |
* The type code is uninterpreted client data which can be set in the constructor. | |
* | |
* @return the type code of this node | |
*/ | |
public int getTypeCode() { | |
return fTypeCode; | |
} | |
/** | |
* Returns this node's id. | |
* It is used in <code>equals</code> and <code>hashcode</code>. | |
* | |
* @return the node's id | |
*/ | |
public String getId() { | |
return fID; | |
} | |
/** | |
* Sets this node's id. | |
* It is used in <code>equals</code> and <code>hashcode</code>. | |
* | |
* @param id the new id for this node | |
*/ | |
public void setId(String id) { | |
fID= id; | |
} | |
/** | |
* Adds the given node as a child. | |
* | |
* @param node the node to add as a child | |
*/ | |
public void addChild(JavaNode node) { | |
if (fChildren == null) | |
fChildren= new ArrayList(); | |
fChildren.add(node); | |
} | |
/* (non Javadoc) | |
* see IStructureComparator.getChildren | |
*/ | |
public Object[] getChildren() { | |
if (fChildren != null) | |
return fChildren.toArray(); | |
return null; | |
} | |
/** | |
* Sets the length of the range of this node. | |
* | |
* @param length the length of the range | |
*/ | |
public void setLength(int length) { | |
fLength= length; | |
} | |
/** | |
* Implementation based on <code>getID</code>. | |
*/ | |
public boolean equals(Object other) { | |
if (other != null && other.getClass() == getClass()) { | |
JavaNode tn= (JavaNode) other; | |
return fTypeCode == tn.fTypeCode && fID.equals(tn.fID); | |
} | |
return super.equals(other); | |
} | |
/** | |
* Implementation based on <code>getID</code>. | |
*/ | |
public int hashCode() { | |
return fID.hashCode(); | |
} | |
/* This version of getContents will be affected by whitespace changes. | |
public String getContents() { | |
char[] b= new char[fLength]; | |
System.arraycopy(fBuffer, fStart, b, 0, fLength); | |
return new String(b); | |
} | |
*/ | |
public String getContents() { | |
char[] b= new char[fLength]; | |
System.arraycopy(fBuffer, fStart, b, 0, fLength); | |
boolean ignoreWhiteSpace= true; | |
if (ignoreWhiteSpace) { | |
// replace comments and whitespace by a single blank | |
StringBuffer buf= new StringBuffer(); | |
// to avoid the trouble when dealing with Unicode | |
// we use the Java scanner to extract non-whitespace and non-comment tokens | |
Scanner scanner= new Scanner(true, true); // however we request Whitespace and Comments | |
scanner.setSourceBuffer(b); | |
try { | |
int token; | |
while ((token= scanner.getNextToken()) != TerminalSymbols.TokenNameEOF) { | |
switch (token) { | |
case Scanner.TokenNameWHITESPACE: | |
case Scanner.TokenNameCOMMENT_BLOCK: | |
case Scanner.TokenNameCOMMENT_JAVADOC: | |
case Scanner.TokenNameCOMMENT_LINE: | |
int l= buf.length(); | |
if (l > 0 && buf.charAt(l-1) != ' ') { | |
buf.append(' '); | |
} | |
break; | |
default: | |
buf.append(b, scanner.startPosition, scanner.currentPosition - scanner.startPosition); | |
buf.append(' '); | |
break; | |
} | |
} | |
return buf.toString(); // success! | |
} catch (InvalidInputException ex) { | |
} | |
} | |
return new String(b); // return original source | |
} | |
} | |