1a8c5343c1849b2b1eec5d01c90d4131e60bdec3
[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 global variables (not parameters)
160    * @return the variables from outside
161    */
162   public List getOutsideVariable() {
163     final ArrayList list = new ArrayList();
164
165     if (statements != null) {
166       for (int i = 0; i < statements.length; i++) {
167         list.addAll(statements[i].getOutsideVariable());
168       }
169     }
170     return list;
171   }
172
173   private List getParameters(final List list) {
174     if (arguments != null) {
175       final Enumeration vars = arguments.keys();
176       while (vars.hasMoreElements()) {
177         list.add(new VariableUsage((String) vars.nextElement(), sourceStart));
178       }
179     }
180     return list;
181   }
182
183   /**
184    * get the modified variables.
185    * @return the variables from we change value
186    */
187   public List getModifiedVariable() {
188     final ArrayList list = new ArrayList();
189     if (statements != null) {
190       for (int i = 0; i < statements.length; i++) {
191         list.addAll(statements[i].getModifiedVariable());
192       }
193     }
194     return list;
195   }
196
197   /**
198    * Get the variables used.
199    * @return the variables used
200    */
201   public List getUsedVariable() {
202     final ArrayList list = new ArrayList();
203     if (statements != null) {
204       for (int i = 0; i < statements.length; i++) {
205         list.addAll(statements[i].getUsedVariable());
206       }
207     }
208     return list;
209   }
210
211   private boolean isVariableDeclaredBefore(List list, VariableUsage var) {
212     final String name = var.getName();
213     final int pos = var.getStartOffset();
214     for (int i = 0; i < list.size(); i++) {
215       VariableUsage variableUsage = (VariableUsage) list.get(i);
216       if (variableUsage.getName().equals(name) && variableUsage.getStartOffset() < pos) {
217         return true;
218       }
219     }
220     return false;
221   }
222
223   /**
224    * This method will analyze the code.
225    */
226   public void analyzeCode() {
227     if (statements != null) {
228       for (int i = 0; i < statements.length; i++) {
229         statements[i].analyzeCode();
230
231       }
232     }
233
234     final List globalsVars = getOutsideVariable();
235     final List modifiedVars = getModifiedVariable();
236     final List parameters = getParameters(new ArrayList());
237
238     final List declaredVars = new ArrayList(globalsVars.size() + modifiedVars.size());
239     declaredVars.addAll(globalsVars);
240     declaredVars.addAll(modifiedVars);
241     declaredVars.addAll(parameters);
242
243     final List usedVars = getUsedVariable();
244     final List readOrWriteVars = new ArrayList(modifiedVars.size()+usedVars.size());
245     readOrWriteVars.addAll(modifiedVars);
246     readOrWriteVars.addAll(usedVars);
247
248     //look for used variables that were not declared before
249     findUnusedParameters(readOrWriteVars,parameters);
250     findUnknownUsedVars(usedVars, declaredVars);
251   }
252
253   /**
254    * This method will add a warning on all unused parameters.
255    * @param vars the used variable list
256    * @param parameters the declared variable list
257    */
258   private void findUnusedParameters(final List vars, final List parameters) {
259     for (int i = 0; i < parameters.size(); i++) {
260       VariableUsage param = ((VariableUsage)parameters.get(i));
261       if (!isVariableInList(param.getName(),vars)) {
262         try {
263           PHPParserSuperclass.setMarker("warning, the parameter "+param.getName() +" seems to be never used in your method",
264                                         param.getStartOffset(),
265                                         param.getStartOffset() + param.getName().length(),
266                                         PHPParserSuperclass.WARNING,
267                                         "");
268         } catch (CoreException e) {
269           PHPeclipsePlugin.log(e);
270         }
271       }
272     }
273   }
274
275   private boolean isVariableInList(final String name, final List list) {
276     for (int i = 0; i < list.size(); i++) {
277       if (((VariableUsage) list.get(i)).getName().equals(name)) {
278         return true;
279       }
280     }
281     return false;
282   }
283
284   /**
285    * This method will add a warning on all used variables in a method that aren't declared before.
286    * @param usedVars the used variable list
287    * @param declaredVars the declared variable list
288    */
289   private void findUnknownUsedVars(final List usedVars, final List declaredVars) {
290     for (int i = 0; i < usedVars.size(); i++) {
291       VariableUsage variableUsage = (VariableUsage) usedVars.get(i);
292       if (variableUsage.getName().equals("this")) continue; // this is a special variable
293       if (!isVariableDeclaredBefore(declaredVars, variableUsage)) {
294         try {
295           PHPParserSuperclass.setMarker("warning, usage of a variable that seems to be unassigned yet : " + variableUsage.getName(),
296                                         variableUsage.getStartOffset(),
297                                         variableUsage.getStartOffset() + variableUsage.getName().length(),
298                                         PHPParserSuperclass.WARNING,
299                                         "");
300         } catch (CoreException e) {
301           PHPeclipsePlugin.log(e);
302         }
303       }
304     }
305   }
306 }