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

# · Java · 425 lines · 271 code · 58 blank · 96 comment · 44 complexity · f846a1706b2a322f71c7ef7031a052ec MD5 · raw file

  1. package net.sourceforge.phpdt.internal.compiler.ast;
  2. import gatchan.phpparser.parser.PHPParseMessageEvent;
  3. import gatchan.phpparser.parser.PHPParser;
  4. import gatchan.phpparser.project.itemfinder.PHPItem;
  5. import net.sourceforge.phpdt.internal.compiler.ast.declarations.VariableUsage;
  6. import net.sourceforge.phpdt.internal.compiler.parser.Outlineable;
  7. import net.sourceforge.phpdt.internal.compiler.parser.OutlineableWithChildren;
  8. import sidekick.IAsset;
  9. import javax.swing.*;
  10. import javax.swing.text.Position;
  11. import java.util.ArrayList;
  12. import java.util.HashSet;
  13. import java.util.List;
  14. import java.util.Set;
  15. /**
  16. * A Method declaration.
  17. *
  18. * @author Matthieu Casanova
  19. */
  20. public class MethodDeclaration extends Statement implements OutlineableWithChildren, IAsset {
  21. private MethodHeader methodHeader;
  22. private Statement[] statements;
  23. private int bodyLineStart;
  24. private int bodyColumnStart;
  25. private int bodyLineEnd;
  26. private int bodyColumnEnd;
  27. /** Tell if the method is a class constructor. */
  28. private boolean isConstructor;
  29. /** The parent object. */
  30. private transient OutlineableWithChildren parent;
  31. /** The outlineable children (those will be in the node array too. */
  32. private final List children = new ArrayList();
  33. private transient Position start;
  34. private transient Position end;
  35. private static Icon icon;
  36. /** The variables assigned in code. This is used during code completion. */
  37. private transient List assignedVariablesInCode;
  38. private static final long serialVersionUID = 8471570829959168564L;
  39. public MethodDeclaration(OutlineableWithChildren parent, MethodHeader methodHeader) {
  40. sourceStart = methodHeader.getSourceStart();
  41. beginLine = methodHeader.getBeginLine();
  42. beginColumn = methodHeader.getBeginColumn();
  43. this.parent = parent;
  44. this.methodHeader = methodHeader;
  45. }
  46. /**
  47. * Return method into String, with a number of tabs
  48. *
  49. * @param tab the number of tabs
  50. *
  51. * @return the String containing the method
  52. */
  53. public String toString(int tab) {
  54. StringBuffer buff = new StringBuffer(200);
  55. buff.append(methodHeader.toString(tab));
  56. buff.append(toStringStatements(tab + 1));
  57. return buff.toString();
  58. }
  59. public String toString() {
  60. return methodHeader.toString();
  61. }
  62. /**
  63. * Return the statements of the method into Strings
  64. *
  65. * @param tab the number of tabs
  66. *
  67. * @return the String containing the statements
  68. */
  69. private String toStringStatements(int tab) {
  70. StringBuffer buff = new StringBuffer(" {");
  71. if (statements != null) {
  72. for (int i = 0; i < statements.length; i++) {
  73. buff.append('\n').append(statements[i].toString(tab));
  74. if (!(statements[i] instanceof Block)) {
  75. buff.append(';');
  76. }
  77. }
  78. }
  79. buff.append('\n').append(tabString(tab == 0 ? 0 : tab - 1)).append('}');
  80. return buff.toString();
  81. }
  82. public void setParent(OutlineableWithChildren parent) {
  83. this.parent = parent;
  84. }
  85. public OutlineableWithChildren getParent() {
  86. return parent;
  87. }
  88. public boolean add(Outlineable o) {
  89. return children.add(o);
  90. }
  91. public Outlineable get(int index) {
  92. return (Outlineable) children.get(index);
  93. }
  94. public int size() {
  95. return children.size();
  96. }
  97. /**
  98. * Get the variables from outside (parameters, globals ...)
  99. *
  100. * @param list the list where we will put variables
  101. */
  102. public void getOutsideVariable(List list) {
  103. }
  104. /**
  105. * get the modified variables.
  106. *
  107. * @param list the list where we will put variables
  108. */
  109. public void getModifiedVariable(List list) {
  110. }
  111. /**
  112. * This method will analyze the code.
  113. *
  114. * @param list the list where we will put variables
  115. */
  116. public void getUsedVariable(List list) {
  117. }
  118. /**
  119. * Get global variables (not parameters).
  120. *
  121. * @param list the list where I will put the variables
  122. */
  123. private void getGlobalVariable(List list) {
  124. if (statements != null) {
  125. for (int i = 0; i < statements.length; i++) {
  126. statements[i].getOutsideVariable(list);
  127. }
  128. }
  129. }
  130. /**
  131. * get the modified variables.
  132. *
  133. * @return the assigned variables in code.
  134. */
  135. private List getAssignedVariableInCode() {
  136. if (assignedVariablesInCode == null) {
  137. assignedVariablesInCode = new ArrayList(50);
  138. if (statements != null) {
  139. for (int i = 0; i < statements.length; i++) {
  140. statements[i].getModifiedVariable(assignedVariablesInCode);
  141. }
  142. }
  143. }
  144. return assignedVariablesInCode;
  145. }
  146. /**
  147. * Get the variables used.
  148. *
  149. * @param list the list where I will put the variables
  150. */
  151. private void getUsedVariableInCode(List list) {
  152. if (statements != null) {
  153. for (int i = 0; i < statements.length; i++) {
  154. statements[i].getUsedVariable(list);
  155. }
  156. }
  157. }
  158. /**
  159. * Returns the last variable assignation with the given name before the line and column.
  160. *
  161. * @param name the name of the variable
  162. * @param line the line
  163. * @param column the column
  164. *
  165. * @return a variable usage or null
  166. */
  167. public VariableUsage getAssignedVariableInCode(String name, int line, int column) {
  168. List assignedVariablesInCode = getAssignedVariableInCode();
  169. VariableUsage found = null;
  170. for (int i = 0; i < assignedVariablesInCode.size(); i++) {
  171. VariableUsage variableUsage = (VariableUsage) assignedVariablesInCode.get(i);
  172. if (variableUsage.getEndLine() > line || (variableUsage.getEndLine() == line && variableUsage.getBeginColumn() > column)) {
  173. // We do not need variables declared after the given line
  174. break;
  175. }
  176. if (variableUsage.getName().equals(name) && (found == null || found.isDeclaredBefore(variableUsage))) {
  177. found = variableUsage;
  178. }
  179. }
  180. return found;
  181. }
  182. private static boolean isVariableDeclaredBefore(List list, VariableUsage var) {
  183. String name = var.getName();
  184. int pos = var.getSourceStart();
  185. for (int i = 0; i < list.size(); i++) {
  186. VariableUsage variableUsage = (VariableUsage) list.get(i);
  187. if (variableUsage.getName().equals(name) && variableUsage.getSourceStart() < pos) {
  188. return true;
  189. }
  190. }
  191. return false;
  192. }
  193. /** This method will analyze the code. */
  194. public void analyzeCode(PHPParser parser) {
  195. methodHeader.analyzeCode(parser);
  196. if (statements != null) {
  197. for (int i = 0; i < statements.length; i++) {
  198. statements[i].analyzeCode(parser);
  199. }
  200. }
  201. List globalsVars = new ArrayList();
  202. getGlobalVariable(globalsVars);
  203. List modifiedVars = getAssignedVariableInCode();
  204. List parameters = new ArrayList(methodHeader.getArgumentsCount());
  205. methodHeader.getParameters(parameters);
  206. List declaredVars = new ArrayList(globalsVars.size() + modifiedVars.size() + parameters.size());
  207. declaredVars.addAll(globalsVars);
  208. declaredVars.addAll(modifiedVars);
  209. declaredVars.addAll(parameters);
  210. List usedVars = new ArrayList();
  211. getUsedVariableInCode(usedVars);
  212. List readOrWriteVars = new ArrayList(modifiedVars.size() + usedVars.size());
  213. readOrWriteVars.addAll(modifiedVars);
  214. readOrWriteVars.addAll(usedVars);
  215. //look for used variables that were not declared before
  216. findUnusedParameters(parser, readOrWriteVars, parameters);
  217. findUnknownUsedVars(parser, usedVars, declaredVars);
  218. }
  219. /**
  220. * This method will add a warning on all unused parameters.
  221. *
  222. * @param parser the php parser
  223. * @param vars the used variable list
  224. * @param parameters the declared variable list
  225. */
  226. private static void findUnusedParameters(PHPParser parser, List vars, List parameters) {
  227. for (int i = 0; i < parameters.size(); i++) {
  228. VariableUsage param = (VariableUsage) parameters.get(i);
  229. if (!isVariableInList(param.getName(), vars)) {
  230. parser.fireParseMessage(new PHPParseMessageEvent(PHPParser.WARNING,
  231. PHPParseMessageEvent.MESSAGE_UNUSED_PARAMETERS,
  232. parser.getPath(),
  233. "warning, the parameter " + param.getName() + " seems to be never used in your method",
  234. param.getSourceStart(),
  235. param.getSourceEnd(),
  236. param.getBeginLine(),
  237. param.getEndLine(),
  238. param.getBeginColumn(),
  239. param.getEndColumn()));
  240. /* fireParseMessage(new PHPParseMessageEvent(PHPParser.WARNING,
  241. parser.getPath(),
  242. "You should use '<?php' instead of '<?' it will avoid some problems with XML",
  243. param.getSourceStart(),
  244. param.getSourceStart() + param.getName().length(),
  245. token.beginLine,
  246. token.endLine,
  247. token.beginColumn,
  248. token.endColumn));*/
  249. }
  250. }
  251. }
  252. /**
  253. * Tell if the list of VariableUsage contains a variable named by the name given.
  254. *
  255. * @param name the variable name
  256. * @param list the list of VariableUsage
  257. *
  258. * @return true if the variable is in the list false otherwise
  259. */
  260. private static boolean isVariableInList(String name, List list) {
  261. for (int i = 0; i < list.size(); i++) {
  262. if (((VariableUsage) list.get(i)).getName().equals(name)) {
  263. return true;
  264. }
  265. }
  266. return false;
  267. }
  268. /**
  269. * This method will add a warning on all used variables in a method that aren't declared before.
  270. *
  271. * @param parser the php parser
  272. * @param usedVars the used variable list
  273. * @param declaredVars the declared variable list
  274. */
  275. private static void findUnknownUsedVars(PHPParser parser, List usedVars, List declaredVars) {
  276. Set list = new HashSet(usedVars.size());
  277. for (int i = 0; i < usedVars.size(); i++) {
  278. VariableUsage variableUsage = (VariableUsage) usedVars.get(i);
  279. if ("this".equals(variableUsage.getName())) continue; // this is a special variable
  280. if (!list.contains(variableUsage.getName()) && !isVariableDeclaredBefore(declaredVars, variableUsage)) {
  281. list.add(variableUsage.getName());
  282. parser.fireParseMessage(new PHPParseMessageEvent(PHPParser.WARNING,
  283. PHPParseMessageEvent.MESSAGE_VARIABLE_MAY_BE_UNASSIGNED,
  284. parser.getPath(),
  285. "warning, usage of a variable that seems to be unassigned yet : " + variableUsage.getName(),
  286. variableUsage.getSourceStart(),
  287. variableUsage.getSourceEnd(),
  288. variableUsage.getBeginLine(),
  289. variableUsage.getEndLine(),
  290. variableUsage.getBeginColumn(),
  291. variableUsage.getEndColumn()));
  292. }
  293. }
  294. }
  295. public String getName() {
  296. return methodHeader.getName();
  297. }
  298. public MethodHeader getMethodHeader() {
  299. return methodHeader;
  300. }
  301. public void setStatements(Statement[] statements) {
  302. this.statements = statements;
  303. }
  304. public int getBodyLineStart() {
  305. return bodyLineStart;
  306. }
  307. public void setBodyLineStart(int bodyLineStart) {
  308. this.bodyLineStart = bodyLineStart;
  309. }
  310. public int getBodyColumnStart() {
  311. return bodyColumnStart;
  312. }
  313. public void setBodyColumnStart(int bodyColumnStart) {
  314. this.bodyColumnStart = bodyColumnStart;
  315. }
  316. public int getBodyLineEnd() {
  317. return bodyLineEnd;
  318. }
  319. public void setBodyLineEnd(int bodyLineEnd) {
  320. this.bodyLineEnd = bodyLineEnd;
  321. setEndLine(bodyLineEnd);
  322. }
  323. public int getBodyColumnEnd() {
  324. return bodyColumnEnd;
  325. }
  326. public void setBodyColumnEnd(int bodyColumnEnd) {
  327. this.bodyColumnEnd = bodyColumnEnd;
  328. setEndColumn(bodyColumnEnd);
  329. }
  330. public int getItemType() {
  331. return PHPItem.METHOD;
  332. }
  333. public Icon getIcon() {
  334. if (icon == null) {
  335. icon = new ImageIcon(MethodDeclaration.class.getResource("/gatchan/phpparser/icons/method.png"));
  336. }
  337. return icon;
  338. }
  339. public Position getStart() {
  340. return start;
  341. }
  342. public void setStart(Position start) {
  343. this.start = start;
  344. }
  345. public Position getEnd() {
  346. return end;
  347. }
  348. public void setEnd(Position end) {
  349. this.end = end;
  350. }
  351. public String getShortString() {
  352. return toString();
  353. }
  354. public String getLongString() {
  355. return toString();
  356. }
  357. public void setName(String name) {
  358. }
  359. public Expression expressionAt(int line, int column) {
  360. if (methodHeader.isAt(line, column)) return methodHeader.expressionAt(line, column);
  361. for (int i = 0; i < statements.length; i++) {
  362. Statement statement = statements[i];
  363. if (statement.isAt(line, column)) return statement.expressionAt(line, column);
  364. }
  365. return null;
  366. }
  367. }