/plugins/PHPParser/tags/v1_2_0_alpha_3/src/net/sourceforge/phpdt/internal/compiler/ast/MethodDeclaration.java

# · Java · 305 lines · 194 code · 40 blank · 71 comment · 28 complexity · 1a8f26307a41ea4fc13fcbeb83faa508 MD5 · raw file

  1. package net.sourceforge.phpdt.internal.compiler.ast;
  2. import net.sourceforge.phpdt.internal.compiler.ast.declarations.VariableUsage;
  3. import net.sourceforge.phpdt.internal.compiler.parser.Outlineable;
  4. import net.sourceforge.phpdt.internal.compiler.parser.OutlineableWithChildren;
  5. import java.util.ArrayList;
  6. import java.util.HashSet;
  7. import java.util.List;
  8. import gatchan.phpparser.parser.PHPParseMessageEvent;
  9. import gatchan.phpparser.parser.PHPParser;
  10. /**
  11. * A Method declaration.
  12. *
  13. * @author Matthieu Casanova
  14. */
  15. public final class MethodDeclaration extends Statement implements OutlineableWithChildren {
  16. private MethodHeader methodHeader;
  17. public Statement[] statements;
  18. private int bodyStart;
  19. private int bodyEnd = -1;
  20. /** Tell if the method is a class constructor. */
  21. public boolean isConstructor;
  22. /** The parent object. */
  23. private transient Object parent;
  24. /** The outlineable children (those will be in the node array too. */
  25. private final ArrayList children = new ArrayList();
  26. public MethodDeclaration(Object parent, MethodHeader methodHeader) {
  27. super(methodHeader.getSourceStart(),
  28. 0,
  29. methodHeader.getBeginLine(),
  30. 0,
  31. methodHeader.getBeginColumn(),
  32. 0);
  33. this.parent = parent;
  34. this.methodHeader = methodHeader;
  35. }
  36. /**
  37. * Return method into String, with a number of tabs
  38. *
  39. * @param tab the number of tabs
  40. *
  41. * @return the String containing the method
  42. */
  43. public String toString(final int tab) {
  44. final StringBuffer buff = new StringBuffer(200);
  45. buff.append(methodHeader.toString(tab));
  46. buff.append(toStringStatements(tab + 1));
  47. return buff.toString();
  48. }
  49. /**
  50. * Return the statements of the method into Strings
  51. *
  52. * @param tab the number of tabs
  53. *
  54. * @return the String containing the statements
  55. */
  56. private String toStringStatements(final int tab) {
  57. final StringBuffer buff = new StringBuffer(" {"); //$NON-NLS-1$
  58. if (statements != null) {
  59. for (int i = 0; i < statements.length; i++) {
  60. buff.append("\n").append(statements[i].toString(tab)); //$NON-NLS-1$
  61. if (!(statements[i] instanceof Block)) {
  62. buff.append(";"); //$NON-NLS-1$
  63. }
  64. }
  65. }
  66. buff.append("\n").append(tabString(tab == 0 ? 0 : tab - 1)).append("}"); //$NON-NLS-2$ //$NON-NLS-1$
  67. return buff.toString();
  68. }
  69. public void setParent(final Object parent) {
  70. this.parent = parent;
  71. }
  72. public Object getParent() {
  73. return parent;
  74. }
  75. public boolean add(final Outlineable o) {
  76. return children.add(o);
  77. }
  78. public Outlineable get(final int index) {
  79. return (Outlineable) children.get(index);
  80. }
  81. public int size() {
  82. return children.size();
  83. }
  84. public String toString() {
  85. return methodHeader.toString();
  86. }
  87. public List getList() {
  88. return children;
  89. }
  90. /**
  91. * Get the variables from outside (parameters, globals ...)
  92. *
  93. * @param list the list where we will put variables
  94. */
  95. public void getOutsideVariable(final List list) {
  96. }
  97. /**
  98. * get the modified variables.
  99. *
  100. * @param list the list where we will put variables
  101. */
  102. public void getModifiedVariable(final List list) {
  103. }
  104. /**
  105. * This method will analyze the code.
  106. *
  107. * @param list the list where we will put variables
  108. */
  109. public void getUsedVariable(final List list) {
  110. }
  111. /** Get global variables (not parameters). */
  112. private void getGlobalVariable(final List list) {
  113. if (statements != null) {
  114. for (int i = 0; i < statements.length; i++) {
  115. statements[i].getOutsideVariable(list);
  116. }
  117. }
  118. }
  119. /** get the modified variables. */
  120. private void getAssignedVariableInCode(final List list) {
  121. if (statements != null) {
  122. for (int i = 0; i < statements.length; i++) {
  123. statements[i].getModifiedVariable(list);
  124. }
  125. }
  126. }
  127. /** Get the variables used. */
  128. private void getUsedVariableInCode(final List list) {
  129. if (statements != null) {
  130. for (int i = 0; i < statements.length; i++) {
  131. statements[i].getUsedVariable(list);
  132. }
  133. }
  134. }
  135. private static boolean isVariableDeclaredBefore(final List list, final VariableUsage var) {
  136. final String name = var.getName();
  137. final int pos = var.getSourceStart();
  138. for (int i = 0; i < list.size(); i++) {
  139. final VariableUsage variableUsage = (VariableUsage) list.get(i);
  140. if (variableUsage.getName().equals(name) && variableUsage.getSourceStart() < pos) {
  141. return true;
  142. }
  143. }
  144. return false;
  145. }
  146. /** This method will analyze the code. */
  147. public void analyzeCode(PHPParser parser) {
  148. if (statements != null) {
  149. for (int i = 0; i < statements.length; i++) {
  150. statements[i].analyzeCode(parser);
  151. }
  152. }
  153. final List globalsVars = new ArrayList();
  154. getGlobalVariable(globalsVars);
  155. final List modifiedVars = new ArrayList();
  156. getAssignedVariableInCode(modifiedVars);
  157. final List parameters = new ArrayList(methodHeader.getArgumentsCount());
  158. methodHeader.getParameters(parameters);
  159. final List declaredVars = new ArrayList(globalsVars.size() + modifiedVars.size());
  160. declaredVars.addAll(globalsVars);
  161. declaredVars.addAll(modifiedVars);
  162. declaredVars.addAll(parameters);
  163. final List usedVars = new ArrayList();
  164. getUsedVariableInCode(usedVars);
  165. final List readOrWriteVars = new ArrayList(modifiedVars.size() + usedVars.size());
  166. readOrWriteVars.addAll(modifiedVars);
  167. readOrWriteVars.addAll(usedVars);
  168. //look for used variables that were not declared before
  169. findUnusedParameters(parser, readOrWriteVars, parameters);
  170. findUnknownUsedVars(parser, usedVars, declaredVars);
  171. }
  172. /**
  173. * This method will add a warning on all unused parameters.
  174. *
  175. * @param vars the used variable list
  176. * @param parameters the declared variable list
  177. */
  178. private static void findUnusedParameters(PHPParser parser, final List vars, final List parameters) {
  179. for (int i = 0; i < parameters.size(); i++) {
  180. final VariableUsage param = (VariableUsage) parameters.get(i);
  181. if (!isVariableInList(param.getName(), vars)) {
  182. parser.fireParseMessage(new PHPParseMessageEvent(PHPParser.WARNING,
  183. PHPParseMessageEvent.MESSAGE_UNUSED_PARAMETERS,
  184. parser.getPath(),
  185. "warning, the parameter " + param.getName() + " seems to be never used in your method",
  186. param.getSourceStart(),
  187. param.getSourceEnd(),
  188. param.getBeginLine(),
  189. param.getEndLine(),
  190. param.getBeginColumn(),
  191. param.getEndColumn()));
  192. /* fireParseMessage(new PHPParseMessageEvent(PHPParser.WARNING,
  193. parser.getPath(),
  194. "You should use '<?php' instead of '<?' it will avoid some problems with XML",
  195. param.getSourceStart(),
  196. param.getSourceStart() + param.getName().length(),
  197. token.beginLine,
  198. token.endLine,
  199. token.beginColumn,
  200. token.endColumn));*/
  201. }
  202. }
  203. }
  204. /**
  205. * Tell if the list of VariableUsage contains a variable named by the name given.
  206. *
  207. * @param name the variable name
  208. * @param list the list of VariableUsage
  209. *
  210. * @return true if the variable is in the list false otherwise
  211. */
  212. private static boolean isVariableInList(final String name, final List list) {
  213. for (int i = 0; i < list.size(); i++) {
  214. if (((VariableUsage) list.get(i)).getName().equals(name)) {
  215. return true;
  216. }
  217. }
  218. return false;
  219. }
  220. /**
  221. * This method will add a warning on all used variables in a method that aren't declared before.
  222. *
  223. * @param usedVars the used variable list
  224. * @param declaredVars the declared variable list
  225. */
  226. private static void findUnknownUsedVars(PHPParser parser, final List usedVars, final List declaredVars) {
  227. final HashSet list = new HashSet(usedVars.size());
  228. for (int i = 0; i < usedVars.size(); i++) {
  229. final VariableUsage variableUsage = (VariableUsage) usedVars.get(i);
  230. if ("this".equals(variableUsage.getName())) continue; // this is a special variable
  231. if (!list.contains(variableUsage.getName()) && !isVariableDeclaredBefore(declaredVars, variableUsage)) {
  232. list.add(variableUsage.getName());
  233. parser.fireParseMessage(new PHPParseMessageEvent(PHPParser.WARNING,
  234. PHPParseMessageEvent.MESSAGE_VARIABLE_MAY_BE_UNASSIGNED,
  235. parser.getPath(),
  236. "warning, usage of a variable that seems to be unassigned yet : " + variableUsage.getName(),
  237. variableUsage.getSourceStart(),
  238. variableUsage.getSourceEnd(),
  239. variableUsage.getBeginLine(),
  240. variableUsage.getEndLine(),
  241. variableUsage.getBeginColumn(),
  242. variableUsage.getEndColumn()));
  243. }
  244. }
  245. }
  246. public String getName() {
  247. return methodHeader.getName();
  248. }
  249. public int getBodyEnd() {
  250. return bodyEnd;
  251. }
  252. public int getBodyStart() {
  253. return bodyStart;
  254. }
  255. public void setBodyStart(int bodyStart) {
  256. this.bodyStart = bodyStart;
  257. }
  258. public void setBodyEnd(int bodyEnd) {
  259. this.sourceEnd = bodyEnd;
  260. this.bodyEnd = bodyEnd;
  261. }
  262. public MethodHeader getMethodHeader() {
  263. return methodHeader;
  264. }
  265. }