package com.aptana.rdt.internal.parser.warnings; import java.util.ArrayList; import java.util.List; import org.jruby.ast.ArgsNode; import org.jruby.ast.ClassNode; import org.jruby.ast.FCallNode; import org.jruby.ast.LocalAsgnNode; import org.rubypeople.rdt.core.parser.warnings.RubyLintVisitor; import org.rubypeople.rdt.internal.core.util.ASTUtil; import com.aptana.rdt.AptanaRDTPlugin; import com.aptana.rdt.IProblem; public class LocalVariablePossibleAttributeAccess extends RubyLintVisitor { private List<LocalAsgnNode> locals = new ArrayList<LocalAsgnNode>(); private List<String> attributes = new ArrayList<String>(); private boolean insideMethodSignature; public LocalVariablePossibleAttributeAccess(String contents) { super(AptanaRDTPlugin.getDefault().getOptions(), contents); } @Override protected String getOptionKey() { return AptanaRDTPlugin.COMPILER_PB_LOCAL_VARIABLE_POSSIBLE_ATTRIBUTE_ACCESS; } @Override public Object visitClassNode(ClassNode iVisited) { locals.clear(); attributes.clear(); return super.visitClassNode(iVisited); } @Override public Object visitLocalAsgnNode(LocalAsgnNode iVisited) { if (!insideMethodSignature) locals.add(iVisited); return super.visitLocalAsgnNode(iVisited); } @Override public Object visitArgsNode(ArgsNode iVisited) { // Don't add if the local being assigned inside method signature insideMethodSignature = true; return super.visitArgsNode(iVisited); } @Override public void exitArgsNode(ArgsNode iVisited) { super.exitArgsNode(iVisited); insideMethodSignature = false; } @Override public Object visitFCallNode(FCallNode iVisited) { String name = iVisited.getName(); if (name.equals("attr_accessor") || name.equals("attr_writer") || name.equals("attr")) { List<String> args = filterColonsFromSymbols(ASTUtil.getArgumentsFromFunctionCall(iVisited)); if (name.equals("attr")) { // second arg must be "true" if (args.size() < 2) { return super.visitFCallNode(iVisited); } if (!args.get(1).equals("true")) return super.visitFCallNode(iVisited); attributes.add(args.get(0)); return super.visitFCallNode(iVisited); } attributes.addAll(args); } return super.visitFCallNode(iVisited); } private List<String> filterColonsFromSymbols(List<String> args) { if (args == null) return null; List<String> newArgs = new ArrayList<String>(); for (String string : args) { if (string.startsWith(":")) { string = string.substring(1); } newArgs.add(string); } return newArgs; } @Override public void exitClassNode(ClassNode iVisited) { for (LocalAsgnNode local : locals) { if (attributes.contains(local.getName())) { createProblem(local.getPosition(), "Local variable assignment might be possible attribute access attempt?"); } } super.exitClassNode(iVisited); } @Override protected int getProblemID() { return IProblem.LocalVariablePossibleAttributeAccess; } }