001: package tide.classsyntax;
002:
003: import tide.sources.SourceFile;
004: import tide.editor.MainEditorFrame;
005: import tide.sources.FileItem;
006: import snow.texteditor.*;
007: import tide.utils.*;
008: import snow.utils.StringUtils;
009: import javaparser.*;
010: import java.util.*;
011:
012: /** Part of an expresion chain like a.b.c()
013: * can be a Constructor, a Method, a Class (static), a Field, a local variable.
014: * Managed from IDChain.
015: * TODO: really simplify.
016: */
017: public final class IDChainElement {
018: // class, method, field, constructor, ...
019: private ElementKind kind = ElementKind.Unknown;
020:
021: public final IDChain iDResolver;
022: private String name; // field or method name
023: private String typeName;
024: private String typeParams;
025: // positive incr for declarations (type), negative incr for names (invocations).
026: // a positive global value means that we have an array object !
027: private int arrayDepth = 0;
028: private String args;
029:
030: // For the element name. javax.swing.JFrame instead of JFrame, if known
031: // inner classes have no fileItem, but maybe a reflected class set
032: // this is also the return types of methods or fields or constructors (constructor=like a method returning an instance)
033: public final RType resolvedType_ = new RType();
034:
035: // for fields and methods
036: public FileItem declaringType = null;
037: // to use for inner classes... and when the resolvedType doesn't exist.
038: //public Class declaringClass = null;
039:
040: // class, method or Constructor corresponding to this element, if reflected !!
041: // caution: this is not the declaring type, but the element itself.
042: public Object reflectedObject = null;
043:
044: // int, double, ...
045: public boolean isPrimitiveType = false;
046:
047: // special case, tells that this is not "static"
048: public boolean isClassCast = false;
049:
050: /** Used to know if chains are valid or not
051: */
052: public boolean isResolved() {
053: if (isPrimitiveType)
054: return true; // ??
055: if (reflectedObject != null)
056: return true;
057: if (resolvedType_.isResolved())
058: return true;
059: return false;
060: }
061:
062: public String getTypeParameters() {
063: return typeParams;
064: }
065:
066: /** Use for methods such as "super()" or "hello(12)"
067: */
068: public IDChainElement(IDChain iDResolver, String methodName,
069: String args, boolean enforceMethod,
070: boolean enforceConstructor) {
071: this .iDResolver = iDResolver;
072: this .name = methodName;
073: this .args = args;
074:
075: if (enforceConstructor) {
076: kind = ElementKind.Constructor;
077: typeName = methodName;
078: } else if (enforceMethod || args != null) {
079: kind = ElementKind.Method;
080: } else {
081: kind = ElementKind.Field;
082: }
083:
084: readNameArrayDepth();
085: }
086:
087: /** For example in the code "Integer.MAX_VALUE"
088: */
089: public void setIsDirectClassCall() {
090:
091: //new Throwable("SET IS DIRECT CLASS CALL").printStackTrace();
092: kind = ElementKind.Class;
093: }
094:
095: /** Called when "this" or "super" calls.
096: */
097: public void setIsConstructorCall(String typeName) {
098: //new Throwable("SET IS CONSTRUCTOR CALL").printStackTrace();
099: kind = ElementKind.Constructor;
100: this .typeName = typeName;
101: this .name = typeName; // to test
102: }
103:
104: /** Just the name of fi match, for example the "javax" package may be present in several
105: * libs!=> don't walk from this fi.
106: */
107: public void setIsPackagePart(FileItem fi) {
108: kind = ElementKind.PackageNameFragment;
109: resolvedType_.fitem = fi;
110: typeName = fi.getJavaName();
111: }
112:
113: /** Name of method or field or class, unresolved.
114: * For example length() in String.length().
115: */
116: public String getName() {
117: return name;
118: }
119:
120: /** For example "String" or "java.lang.String".
121: * Declaring type of this element.
122: */
123: public String getTypeMaybeUnresolved() {
124: return typeName;
125: }
126:
127: /** Maybe unresolved.
128: */
129: public void setTypeName(String t) {
130: typeName = t;
131: }
132:
133: /** As <String> for the type Vector in Vector<String>
134: */
135: public void setTypeParameters(String p) {
136: if (typeParams != null && typeParams.length() > 0) {
137: new Throwable("already set:" + typeParams)
138: .printStackTrace();
139: }
140: this .typeParams = p;
141: }
142:
143: public int getArrayDepth() {
144: return this .arrayDepth;
145: }
146:
147: /** Either class name of reflectedObject (if class) or resolvedType type if non null or the simple type name.
148: * For methods and fields, this gives the return type, NOT the declaring class. (use the method in IDChain for that)
149: */
150: public String getTypeMaybeResolved() {
151: if (reflectedObject instanceof Class) {
152: return ((Class) reflectedObject).getName();
153: } else if (resolvedType_.isResolved()) {
154: return resolvedType_.getJavaName();
155: } else {
156: return getTypeMaybeUnresolved();
157: }
158: }
159:
160: private void readNameArrayDepth() // "..." varargs are also coming here as "[]"
161: {
162: if (name != null && name.indexOf('[') > 0) {
163: arrayDepth -= StringUtils.count(name, '['); // NEG !
164: name = name.substring(0, name.indexOf('['));
165: }
166: }
167:
168: public ElementKind getKind() {
169: return kind;
170: }
171:
172: /** For example. String[] or LLjava.lang.String;; or <pre>Vector<String></pre> for variables...
173: * These are the types as declared, for example in arguments (String[]).
174: * This is the declaring type of this element.
175: */
176: public void setTypeWithParamsAndResolve(String tp) {
177: //MainEditorFrame.debugOut("setTypeWithParamsAndResolve: "+tp+" for name="+this.name);
178: //new Throwable(tp).printStackTrace();
179:
180: String[] tt = SyntaxUtils.splitTypeParams(tp);
181: if (tt != null) {
182: typeName = tt[0];
183: typeParams = tt[1];
184: MainEditorFrame.debugOut("Type name=" + typeName
185: + ", tpar=" + typeParams + " for element " + name);
186:
187: // detect array depths !
188: if (typeName != null) {
189: if (typeName.endsWith("[I")) {
190: arrayDepth += StringUtils.count(typeName, '[');
191: typeName = "int";
192: } else if (typeName.endsWith("[Z")) {
193: arrayDepth += StringUtils.count(typeName, '[');
194: typeName = "boolean";
195: } else if (typeName.endsWith("[B")) {
196: arrayDepth += StringUtils.count(typeName, '[');
197: typeName = "byte";
198: } else if (typeName.endsWith("[C")) {
199: arrayDepth += StringUtils.count(typeName, '[');
200: typeName = "char";
201: } else if (typeName.endsWith("[S")) {
202: arrayDepth += StringUtils.count(typeName, '[');
203: typeName = "short";
204: } else if (typeName.endsWith("[D")) {
205: arrayDepth += StringUtils.count(typeName, '[');
206: typeName = "double";
207: } else if (typeName.endsWith("[F")) {
208: arrayDepth += StringUtils.count(typeName, '[');
209: typeName = "float";
210: } else if (typeName.endsWith(";")) // [[[Lxxx; // reflection arrays
211: {
212: // count the [
213: while (typeName.startsWith("[")) {
214: typeName = typeName.substring(1);
215: arrayDepth += 1;
216: }
217: // remove the ";"
218: typeName = typeName.substring(0,
219: typeName.length() - 1);
220: } else if (typeName.indexOf('[') > 0) //"..." are also coming as "[]"
221: {
222: arrayDepth += StringUtils.count(typeName, '['); // POS
223: typeName = typeName.substring(0, typeName
224: .indexOf('['));
225: }
226: }
227: }
228:
229: isPrimitiveType = SyntaxUtils.isPrimitiveType(typeName);
230:
231: if (isPrimitiveType) {
232: resolvedType_.primitiveType = typeName; // not used now.
233: } else {
234: // resolve if not already
235: if (typeName != null && !resolvedType_.isResolved()) {
236: if (typeName.indexOf('$') > 0) {
237: // maybe already resolved, as an inner class
238: MainEditorFrame.debugOut("look for inner class "
239: + typeName);
240: Class c = iDResolver.getClassForName(typeName);
241: // TODO
242: this .resolvedType_.rclass = c;
243: // kind = ElementKind.Class;
244:
245: } else {
246: // always use the imports, also if not first,
247: MainEditorFrame.debugOut("locate using imports: "
248: + typeName);
249: resolvedType_.fitem = iDResolver
250: .locateTypeUsingImports(typeName);
251:
252: if (!resolvedType_.isResolved()) {
253: MainEditorFrame.debugOut("not found...");
254:
255: // well, yes, happends...
256: // maybe an inner class here... A.B.C
257: // so, try to locate A (TODO: javax.swing.XXX.YYY will not be found, => one has to try all subsequences)
258: int pos = typeName.indexOf(".");
259: if (pos > 0) {
260: String partype = typeName.substring(0, pos);
261: MainEditorFrame
262: .debugOut("Looking for enclosing type "
263: + partype);
264: FileItem pit = iDResolver
265: .locateTypeUsingImports(partype);
266: if (pit != null) {
267: //
268: String jn = pit.getJavaName()
269: + typeName.substring(pos)
270: .replace('.', '$');
271: MainEditorFrame
272: .debugOut("found enclosing type "
273: + pit
274: + " for "
275: + typeName
276: + ", try to locate "
277: + jn);
278:
279: Class c = iDResolver
280: .getClassForName(jn);
281: this .resolvedType_.rclass = c;
282: }
283: } else // [Feb2008]
284: {
285:
286: MainEditorFrame
287: .debugOut("Looking for enclosing type "
288: + typeName);
289: SourceFile sf = (SourceFile) this .iDResolver.source;
290: //System.out.println("declared in src: "+ sf.sourceFileDependencies.getDeclaredTypesNames_REF_());
291: // SRC.INT1, ... SRC.INT1.XX, YYY, ...
292: for (String declType : sf.sourceFileDependencies
293: .getDeclaredTypesNames_REF_()) {
294: if (declType.endsWith(typeName)) {
295: MainEditorFrame
296: .debugOut("FOUND INNER TYPE "
297: + declType); // ex: ClassC.DDD
298: // sf.getJavaName() = test.ClassC
299: String jn = "";
300: //if(declType.startsWith( sf.getJavaPartName()))
301: {
302: jn = (sf.getPackageName()
303: .length() > 0 ? sf
304: .getPackageName()
305: + "." : "")
306: + declType.replace('.',
307: '$');
308: }
309: /*else
310: {
311: jn = sf.getJavaName()+"."+declType.replace('.','$');
312: }*/
313:
314: Class c = iDResolver
315: .getClassForName(jn);
316: //System.out.println("class="+c);
317: this .resolvedType_.rclass = c;
318:
319: }
320: }
321: }
322: }
323: }
324: // TODO: look without imports if not found ??
325: }
326: }
327:
328: // for methods and fields, look at the declaring class
329: if (declaringType != null) {
330: if (kind == ElementKind.Field) {
331: declaringType = iDResolver
332: .getDeclaringClassForField(this );
333: } else if (kind == ElementKind.Method) {
334: declaringType = iDResolver
335: .getDeclaringClassForMethod(this );
336: MainEditorFrame.debugOut("Method " + getName()
337: + "() type = " + this .getTypeMaybeResolved());
338: }
339: }
340:
341: }
342:
343: /** Used for debug !
344: */
345: @Override
346: public String toString() {
347: StringBuilder sb = new StringBuilder("" + kind + " ");
348: String type = this .getTypeMaybeResolved();
349:
350: if (kind == ElementKind.Class) {
351: sb.append(type);
352: } else if (kind == ElementKind.Method) {
353: sb.append(name + " (args=" + args + ", ret=" + type);
354: if (typeParams != null)
355: sb.append(", type params=" + typeParams);
356: sb.append(")");
357: } else if (kind == ElementKind.Field) {
358: sb.append(name + " (type=" + type);
359: if (typeParams != null)
360: sb.append(", type params=" + typeParams);
361: sb.append(")");
362: } else if (kind == ElementKind.Constructor) {
363: sb.append(name + " (args=" + args + ", ret=" + type);
364: if (typeParams != null)
365: sb.append(", type params=" + typeParams);
366: sb.append(")");
367: } else if (kind == ElementKind.PackageNameFragment) {
368: sb.append(name);
369: } else {
370: sb.append("??????k=" + kind);
371: }
372:
373: if (arrayDepth != 0) {
374: sb.append(" (arraydepth=" + arrayDepth + ")");
375: }
376:
377: /* if(!resolved && reflectedObject==null)
378: {
379: sb.append(" (NOT resolved)");
380: }*/
381:
382: if (declaringType != null) {
383: sb.append(", declaringType="
384: + declaringType.getJavaPartName());
385: }
386:
387: return sb.toString();
388: }
389:
390: }
|