1 package net.sourceforge.phpdt.internal.compiler.ast;
3 import java.util.ArrayList;
6 import net.sourceforge.phpdt.internal.compiler.ast.declarations.VariableUsage;
7 import net.sourceforge.phpdt.internal.compiler.parser.Outlineable;
8 import net.sourceforge.phpdt.internal.compiler.parser.OutlineableWithChildren;
9 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
10 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
12 import org.eclipse.core.runtime.CoreException;
13 import org.eclipse.jface.resource.ImageDescriptor;
14 import org.eclipse.jface.text.Position;
16 import test.PHPParserSuperclass;
19 * A Method declaration.
20 * @author Matthieu Casanova
22 public final class MethodDeclaration extends Statement implements OutlineableWithChildren {
24 /** The name of the method. */
25 public final String name;
26 private final ArrayList arguments;
29 public Statement[] statements;
30 private final int bodyStart;
31 private int bodyEnd = -1;
32 /** Tell if the method is a class constructor. */
33 public boolean isConstructor;
35 /** The parent object. */
36 private Object parent;
37 /** The outlineable children (those will be in the node array too. */
38 private final ArrayList children = new ArrayList();
40 /** Tell if the method returns a reference. */
41 private final boolean reference;
43 private final Position position;
45 public MethodDeclaration(final Object parent,
47 final ArrayList arguments,
48 final boolean reference,
49 final int sourceStart,
53 super(sourceStart, sourceEnd);
55 this.arguments = arguments;
57 this.reference = reference;
58 this.bodyStart = bodyStart;
59 this.bodyEnd = bodyEnd;
60 position = new Position(sourceStart, sourceEnd);
64 * Return method into String, with a number of tabs
65 * @param tab the number of tabs
66 * @return the String containing the method
68 public String toString(final int tab) {
69 final StringBuffer buff = new StringBuffer(tabString(tab));
70 buff.append(toStringHeader());
71 buff.append(toStringStatements(tab + 1));
72 return buff.toString();
75 private String toStringHeader() {
76 return "function " + toString();
80 * Return the statements of the method into Strings
81 * @param tab the number of tabs
82 * @return the String containing the statements
84 private String toStringStatements(final int tab) {
85 final StringBuffer buff = new StringBuffer(" {"); //$NON-NLS-1$
86 if (statements != null) {
87 for (int i = 0; i < statements.length; i++) {
88 buff.append("\n").append(statements[i].toString(tab)); //$NON-NLS-1$
89 if (!(statements[i] instanceof Block)) {
90 buff.append(";"); //$NON-NLS-1$
94 buff.append("\n").append(tabString(tab == 0 ? 0 : tab - 1)).append("}"); //$NON-NLS-2$ //$NON-NLS-1$
95 return buff.toString();
99 * Get the image of a class.
100 * @return the image that represents a php class
102 public ImageDescriptor getImage() {
103 return PHPUiImages.DESC_FUN;
106 public void setParent(final Object parent) {
107 this.parent = parent;
110 public Object getParent() {
114 public boolean add(final Outlineable o) {
115 return children.add(o);
118 public Outlineable get(final int index) {
119 return (Outlineable) children.get(index);
123 return children.size();
126 public String toString() {
127 final StringBuffer buff = new StringBuffer();
129 buff.append("&");//$NON-NLS-1$
131 buff.append(name).append("(");//$NON-NLS-1$
133 if (arguments != null) {
134 for (int i = 0; i < arguments.size(); i++) {
135 final VariableDeclaration o = (VariableDeclaration) arguments.get(i);
136 buff.append(o.toStringExpression());
137 if (i != (arguments.size() - 1)) {
138 buff.append(", "); //$NON-NLS-1$
142 buff.append(")"); //$NON-NLS-1$
143 return buff.toString();
146 public Position getPosition() {
150 public List getList() {
154 /** no outside variables. */
155 public void getOutsideVariable(final List list) {}
157 public void getModifiedVariable(final List list) {}
159 public void getUsedVariable(final List list) {}
162 * Get global variables (not parameters).
164 private void getGlobalVariable(final List list) {
165 if (statements != null) {
166 for (int i = 0; i < statements.length; i++) {
167 statements[i].getOutsideVariable(list);
172 private void getParameters(final List list) {
173 if (arguments != null) {
174 for (int i = 0; i < arguments.size(); i++) {
175 final VariableDeclaration variable = (VariableDeclaration) arguments.get(i);
176 list.add(new VariableUsage(variable.name(), variable.sourceStart));
182 * get the modified variables.
184 private void getAssignedVariableInCode(final List list) {
185 if (statements != null) {
186 for (int i = 0; i < statements.length; i++) {
187 statements[i].getModifiedVariable(list);
193 * Get the variables used.
195 private void getUsedVariableInCode(final List list) {
196 if (statements != null) {
197 for (int i = 0; i < statements.length; i++) {
198 statements[i].getUsedVariable(list);
203 private static boolean isVariableDeclaredBefore(final List list, final VariableUsage var) {
204 final String name = var.getName();
205 final int pos = var.getStartOffset();
206 for (int i = 0; i < list.size(); i++) {
207 final VariableUsage variableUsage = (VariableUsage) list.get(i);
208 if (variableUsage.getName().equals(name) && variableUsage.getStartOffset() < pos) {
215 /** This method will analyze the code. */
216 public void analyzeCode() {
217 if (statements != null) {
218 for (int i = 0; i < statements.length; i++) {
219 statements[i].analyzeCode();
224 final List globalsVars = new ArrayList();
225 getGlobalVariable(globalsVars);
226 final List modifiedVars = new ArrayList();
227 getAssignedVariableInCode(modifiedVars);
228 final List parameters = new ArrayList(arguments.size());
229 getParameters(parameters);
231 final List declaredVars = new ArrayList(globalsVars.size() + modifiedVars.size());
232 declaredVars.addAll(globalsVars);
233 declaredVars.addAll(modifiedVars);
234 declaredVars.addAll(parameters);
236 final List usedVars = new ArrayList();
237 getUsedVariableInCode(usedVars);
238 final List readOrWriteVars = new ArrayList(modifiedVars.size() + usedVars.size());
239 readOrWriteVars.addAll(modifiedVars);
240 readOrWriteVars.addAll(usedVars);
242 //look for used variables that were not declared before
243 findUnusedParameters(readOrWriteVars, parameters);
244 findUnknownUsedVars(usedVars, declaredVars);
248 * This method will add a warning on all unused parameters.
249 * @param vars the used variable list
250 * @param parameters the declared variable list
252 private static void findUnusedParameters(final List vars, final List parameters) {
253 for (int i = 0; i < parameters.size(); i++) {
254 final VariableUsage param = (VariableUsage) parameters.get(i);
255 if (!isVariableInList(param.getName(), vars)) {
257 PHPParserSuperclass.setMarker(
258 "warning, the parameter " + param.getName() + " seems to be never used in your method",
259 param.getStartOffset(),
260 param.getStartOffset() + param.getName().length(),
261 PHPParserSuperclass.WARNING,
263 } catch (CoreException e) {
264 PHPeclipsePlugin.log(e);
270 private static boolean isVariableInList(final String name, final List list) {
271 for (int i = 0; i < list.size(); i++) {
272 if (((VariableUsage) list.get(i)).getName().equals(name)) {
280 * This method will add a warning on all used variables in a method that aren't declared before.
281 * @param usedVars the used variable list
282 * @param declaredVars the declared variable list
284 private static void findUnknownUsedVars(final List usedVars, final List declaredVars) {
285 for (int i = 0; i < usedVars.size(); i++) {
286 final VariableUsage variableUsage = (VariableUsage) usedVars.get(i);
287 if ("this".equals(variableUsage.getName())) continue; // this is a special variable
288 if (!isVariableDeclaredBefore(declaredVars, variableUsage)) {
290 PHPParserSuperclass.setMarker(
291 "warning, usage of a variable that seems to be unassigned yet : " + variableUsage.getName(),
292 variableUsage.getStartOffset(),
293 variableUsage.getStartOffset() + variableUsage.getName().length(),
294 PHPParserSuperclass.WARNING,
296 } catch (CoreException e) {
297 PHPeclipsePlugin.log(e);