a bugfix on used variables report
[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 String 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 String name,
48                            final Hashtable arguments,
49                            final boolean reference,
50                            final int sourceStart,
51                            final int sourceEnd,
52                            final int bodyStart,
53                            final int bodyEnd) {
54     super(sourceStart, sourceEnd);
55     this.name = name;
56     this.arguments = arguments;
57     this.parent = parent;
58     this.reference = reference;
59     this.bodyStart = bodyStart;
60     this.bodyEnd = bodyEnd;
61     position = new Position(sourceStart, sourceEnd);
62   }
63
64   /**
65    * Return method into String, with a number of tabs
66    * @param tab the number of tabs
67    * @return the String containing the method
68    */
69   public String toString(final int tab) {
70     final StringBuffer buff = new StringBuffer(tabString(tab));
71     buff.append(toStringHeader());
72     buff.append(toStringStatements(tab + 1));
73     return buff.toString();
74   }
75
76   public String toStringHeader() {
77     return "function " + toString();
78   }
79
80   /**
81    * Return the statements of the method into Strings
82    * @param tab the number of tabs
83    * @return the String containing the statements
84    */
85   public String toStringStatements(final int tab) {
86     final StringBuffer buff = new StringBuffer(" {"); //$NON-NLS-1$
87     if (statements != null) {
88       for (int i = 0; i < statements.length; i++) {
89         buff.append("\n").append(statements[i].toString(tab)); //$NON-NLS-1$
90         if (!(statements[i] instanceof Block)) {
91           buff.append(";"); //$NON-NLS-1$
92         }
93       }
94     }
95     buff.append("\n").append(tabString(tab == 0 ? 0 : tab - 1)).append("}"); //$NON-NLS-2$ //$NON-NLS-1$
96     return buff.toString();
97   }
98
99   /**
100    * Get the image of a class.
101    * @return the image that represents a php class
102    */
103   public ImageDescriptor getImage() {
104     return PHPUiImages.DESC_FUN;
105   }
106
107   public void setParent(final Object parent) {
108     this.parent = parent;
109   }
110
111   public Object getParent() {
112     return parent;
113   }
114
115   public boolean add(final Outlineable o) {
116     return children.add(o);
117   }
118
119   public Outlineable get(final int index) {
120     return (Outlineable) children.get(index);
121   }
122
123   public int size() {
124     return children.size();
125   }
126
127   public String toString() {
128     final StringBuffer buff = new StringBuffer();
129     if (reference) {
130       buff.append("&");//$NON-NLS-1$
131     }
132     buff.append(name).append("(");//$NON-NLS-1$
133
134     if (arguments != null) {
135       final Enumeration values = arguments.elements();
136       int i = 0;
137       while (values.hasMoreElements()) {
138         final VariableDeclaration o = (VariableDeclaration) values.nextElement();
139         buff.append(o.toStringExpression());
140         if (i != (arguments.size() - 1)) {
141           buff.append(", "); //$NON-NLS-1$
142         }
143         i++;
144       }
145     }
146     buff.append(")"); //$NON-NLS-1$
147     return buff.toString();
148   }
149
150   public Position getPosition() {
151     return position;
152   }
153
154   public List getList() {
155     return children;
156   }
157
158   /**
159    * Get the variables from outside (parameters, globals ...)
160    * @return the variables from outside
161    */
162   public List getOutsideVariable() {
163     final ArrayList list = new ArrayList();
164     if (arguments != null) {
165       final Enumeration vars = arguments.keys();
166       while (vars.hasMoreElements()) {
167         list.add(new VariableUsage((String) vars.nextElement(), sourceStart));
168       }
169     }
170
171     if (statements != null) {
172       for (int i = 0; i < statements.length; i++) {
173         list.addAll(statements[i].getOutsideVariable());
174       }
175     }
176     return list;
177   }
178
179   /**
180    * get the modified variables.
181    * @return the variables from we change value
182    */
183   public List getModifiedVariable() {
184     final ArrayList list = new ArrayList();
185     if (statements != null) {
186       for (int i = 0; i < statements.length; i++) {
187         list.addAll(statements[i].getModifiedVariable());
188       }
189     }
190     return list;
191   }
192
193   /**
194    * Get the variables used.
195    * @return the variables used
196    */
197   public List getUsedVariable() {
198     final ArrayList list = new ArrayList();
199     if (statements != null) {
200       for (int i = 0; i < statements.length; i++) {
201         list.addAll(statements[i].getUsedVariable());
202       }
203     }
204     return list;
205   }
206
207   private boolean isVariableDeclaredBefore(List list, VariableUsage var) {
208     final String name = var.getName();
209     final int pos = var.getStartOffset();
210     for (int i = 0; i < list.size(); i++) {
211       VariableUsage variableUsage = (VariableUsage) list.get(i);
212       if (variableUsage.getName().equals(name) && variableUsage.getStartOffset() < pos) {
213         return true;
214       }
215     }
216     return false;
217   }
218
219   private void dumpList(List list, String name) {
220     StringBuffer buff = new StringBuffer(name).append("\n");
221     for (int i = 0; i < list.size(); i++) {
222       buff.append(list.get(i).toString()).append("\n");
223     }
224     if (PHPeclipsePlugin.DEBUG) {
225       PHPeclipsePlugin.log(1, buff.toString());
226     }
227   }
228
229   /**
230    * This method will analyze the code.
231    */
232   public void analyzeCode() {
233     final List outsideVars = getOutsideVariable();
234     final List modifiedVars = getModifiedVariable();
235
236     final List declaredVars = new ArrayList(outsideVars.size() + modifiedVars.size());
237     declaredVars.addAll(outsideVars);
238     declaredVars.addAll(modifiedVars);
239
240     final List usedVars = getUsedVariable();
241
242 /*    dumpList(outsideVars, "outside");
243     dumpList(modifiedVars, "modified");
244     dumpList(usedVars, "used");  */
245
246
247     //look for used variables that were not declared before
248     findUnknownUsedVars(usedVars, declaredVars);
249   }
250
251   /**
252    * This method will add a warning on all used variables in a method that aren't declared before.
253    * @param usedVars the used variable list
254    * @param declaredVars the declared variable list
255    */
256   private void findUnknownUsedVars(final List usedVars, final List declaredVars) {
257     for (int i = 0; i < usedVars.size(); i++) {
258       VariableUsage variableUsage = (VariableUsage) usedVars.get(i);
259       if (variableUsage.getName().equals("this")) continue; // this is a special variable
260       if (!isVariableDeclaredBefore(declaredVars, variableUsage)) {
261         try {
262           PHPParserSuperclass.setMarker("warning, usage of an unknown variable : " + variableUsage.getName(),
263                                         variableUsage.getStartOffset(),
264                                         variableUsage.getStartOffset() + variableUsage.getName().length(),
265                                         PHPParserSuperclass.WARNING,
266                                         "");
267         } catch (CoreException e) {
268           PHPeclipsePlugin.log(e);
269         }
270       }
271     }
272   }
273 }