a small bugfix
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / MethodDeclaration.java
1 package net.sourceforge.phpdt.internal.compiler.ast;
2
3 import net.sourceforge.phpdt.internal.compiler.parser.OutlineableWithChildren;
4 import net.sourceforge.phpdt.internal.compiler.parser.Outlineable;
5 import net.sourceforge.phpdt.internal.compiler.ast.declarations.VariableUsage;
6 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
7 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
8 import org.eclipse.jface.resource.ImageDescriptor;
9 import org.eclipse.jface.text.Position;
10 import org.eclipse.core.runtime.CoreException;
11
12 import java.util.Hashtable;
13 import java.util.Enumeration;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import test.PHPParserSuperclass;
18
19 /**
20  * A Method declaration.
21  * @author Matthieu Casanova
22  */
23 public class MethodDeclaration extends Statement implements OutlineableWithChildren {
24
25   /** The name of the method. */
26   public char[] name;
27   public Hashtable arguments;
28
29
30   public Statement[] statements;
31   public int bodyStart;
32   public int bodyEnd = -1;
33   /** Tell if the method is a class constructor. */
34   public boolean isConstructor;
35
36   /** The parent object. */
37   private Object parent;
38   /** The outlineable children (those will be in the node array too. */
39   private ArrayList children = new ArrayList();
40
41   /** Tell if the method returns a reference. */
42   public boolean reference;
43
44   private Position position;
45
46   public MethodDeclaration(final Object parent,
47                            final char[] name,
48                            final Hashtable arguments,
49                            final boolean reference,
50                            final int sourceStart,
51                            final int sourceEnd) {
52     super(sourceStart, sourceEnd);
53     this.name = name;
54     this.arguments = arguments;
55     this.parent = parent;
56     this.reference = reference;
57     position = new Position(sourceStart, sourceEnd);
58   }
59
60   /**
61    * Return method into String, with a number of tabs
62    * @param tab the number of tabs
63    * @return the String containing the method
64    */
65   public String toString(final int tab) {
66     final StringBuffer buff = new StringBuffer(tabString(tab));
67     buff.append(toStringHeader());
68     buff.append(toStringStatements(tab + 1));
69     return buff.toString();
70   }
71
72   public String toStringHeader() {
73     return "function " + toString();
74   }
75
76   /**
77    * Return the statements of the method into Strings
78    * @param tab the number of tabs
79    * @return the String containing the statements
80    */
81   public String toStringStatements(final int tab) {
82     final StringBuffer buff = new StringBuffer(" {"); //$NON-NLS-1$
83     if (statements != null) {
84       for (int i = 0; i < statements.length; i++) {
85         buff.append("\n").append(statements[i].toString(tab)); //$NON-NLS-1$
86         if (!(statements[i] instanceof Block)) {
87           buff.append(";"); //$NON-NLS-1$
88         }
89       }
90     }
91     buff.append("\n").append(tabString(tab == 0 ? 0 : tab - 1)).append("}"); //$NON-NLS-2$ //$NON-NLS-1$
92     return buff.toString();
93   }
94
95   /**
96    * Get the image of a class.
97    * @return the image that represents a php class
98    */
99   public ImageDescriptor getImage() {
100     return PHPUiImages.DESC_FUN;
101   }
102
103   public void setParent(final Object parent) {
104     this.parent = parent;
105   }
106
107   public Object getParent() {
108     return parent;
109   }
110
111   public boolean add(final Outlineable o) {
112     return children.add(o);
113   }
114
115   public Outlineable get(final int index) {
116     return (Outlineable) children.get(index);
117   }
118
119   public int size() {
120     return children.size();
121   }
122
123   public String toString() {
124     final StringBuffer buff = new StringBuffer();
125     if (reference) {
126       buff.append("&");//$NON-NLS-1$
127     }
128     buff.append(name).append("(");//$NON-NLS-1$
129
130     if (arguments != null) {
131       final Enumeration values = arguments.elements();
132       int i = 0;
133       while (values.hasMoreElements()) {
134         final VariableDeclaration o = (VariableDeclaration) values.nextElement();
135         buff.append(o.toStringExpression());
136         if (i != (arguments.size() - 1)) {
137           buff.append(", "); //$NON-NLS-1$
138         }
139         i++;
140       }
141     }
142     buff.append(")"); //$NON-NLS-1$
143     return buff.toString();
144   }
145
146   public Position getPosition() {
147     return position;
148   }
149
150   public List getList() {
151     return children;
152   }
153
154   /**
155    * Get the variables from outside (parameters, globals ...)
156    * @return the variables from outside
157    */
158   public List getOutsideVariable() {
159     final ArrayList list = new ArrayList();
160     if (arguments != null) {
161       final Enumeration vars = arguments.keys();
162       while (vars.hasMoreElements()) {
163         list.add(new VariableUsage((String) vars.nextElement(), sourceStart));
164       }
165     }
166
167     if (statements != null) {
168       for (int i = 0; i < statements.length; i++) {
169         list.addAll(statements[i].getOutsideVariable());
170       }
171     }
172     return list;
173   }
174
175   /**
176    * get the modified variables.
177    * @return the variables from we change value
178    */
179   public List getModifiedVariable() {
180     final ArrayList list = new ArrayList();
181     if (statements != null) {
182       for (int i = 0; i < statements.length; i++) {
183         list.addAll(statements[i].getModifiedVariable());
184       }
185     }
186     return list;
187   }
188
189   /**
190    * Get the variables used.
191    * @return the variables used
192    */
193   public List getUsedVariable() {
194     final ArrayList list = new ArrayList();
195     if (statements != null) {
196       for (int i = 0; i < statements.length; i++) {
197         list.addAll(statements[i].getUsedVariable());
198       }
199     }
200     return list;
201   }
202
203   private boolean isVariableDeclaredBefore(List list, VariableUsage var) {
204     final String name = var.getName();
205     final int pos = var.getStartOffset();
206     for (int i = 0; i < list.size(); i++) {
207       VariableUsage variableUsage = (VariableUsage) list.get(i);
208       if (variableUsage.getName().equals(name) && variableUsage.getStartOffset() < pos) {
209         return true;
210       }
211     }
212     return false;
213   }
214
215   private void dumpList(List list, String name) {
216     StringBuffer buff = new StringBuffer(name).append("\n");
217     for (int i = 0; i < list.size(); i++) {
218       buff.append(list.get(i).toString()).append("\n");
219     }
220     if (PHPeclipsePlugin.DEBUG) {
221       PHPeclipsePlugin.log(1, buff.toString());
222     }
223   }
224
225   /**
226    * This method will analyze the code.
227    */
228   public void analyzeCode() {
229     final List outsideVars = getOutsideVariable();
230     final List modifiedVars = getModifiedVariable();
231
232     final List declaredVars = new ArrayList(outsideVars.size() + modifiedVars.size());
233     declaredVars.addAll(outsideVars);
234     declaredVars.addAll(modifiedVars);
235
236     final List usedVars = getUsedVariable();
237
238 /*    dumpList(outsideVars, "outside");
239     dumpList(modifiedVars, "modified");
240     dumpList(usedVars, "used");  */
241
242
243     //look for used variables that were not declared before
244     findUnknownUsedVars(usedVars, declaredVars);
245   }
246
247   /**
248    * This method will add a warning on all used variables in a method that aren't declared before.
249    * @param usedVars the used variable list
250    * @param declaredVars the declared variable list
251    */
252   private void findUnknownUsedVars(final List usedVars, final List declaredVars) {
253     for (int i = 0; i < usedVars.size(); i++) {
254       VariableUsage variableUsage = (VariableUsage) usedVars.get(i);
255       if (!isVariableDeclaredBefore(declaredVars, variableUsage)) {
256         try {
257           PHPParserSuperclass.setMarker("warning, usage of an unknown variable : " + variableUsage.getName(),
258                                         variableUsage.getStartOffset(),
259                                         variableUsage.getStartOffset() + variableUsage.getName().length(),
260                                         PHPParserSuperclass.WARNING,
261                                         "");
262         } catch (CoreException e) {
263           PHPeclipsePlugin.log(e);
264         }
265       }
266     }
267   }
268 }