1 19 package org.netbeans.modules.ruby; 20 21 import java.util.ArrayList ; 22 import java.util.HashMap ; 23 import java.util.List ; 24 import java.util.Map ; 25 26 import org.jruby.ast.AliasNode; 27 import org.jruby.ast.ArgsNode; 28 import org.jruby.ast.ArgumentNode; 29 import org.jruby.ast.DAsgnNode; 30 import org.jruby.ast.DVarNode; 31 import org.jruby.ast.DefnNode; 32 import org.jruby.ast.DefsNode; 33 import org.jruby.ast.FCallNode; 34 import org.jruby.ast.ListNode; 35 import org.jruby.ast.LocalAsgnNode; 36 import org.jruby.ast.LocalVarNode; 37 import org.jruby.ast.Node; 38 import org.jruby.ast.VCallNode; 39 import org.netbeans.api.gsf.ColoringAttributes; 40 import org.netbeans.api.gsf.CompilationInfo; 41 import org.netbeans.api.gsf.OffsetRange; 42 import org.netbeans.api.gsf.SemanticAnalyzer; 43 44 45 55 public class SemanticAnalysis implements SemanticAnalyzer { 56 private boolean cancelled; 57 private Map <OffsetRange, ColoringAttributes> semanticHighlights; 58 59 public SemanticAnalysis() { 60 } 61 62 public Map <OffsetRange, ColoringAttributes> getHighlights() { 63 return semanticHighlights; 64 } 65 66 protected final synchronized boolean isCancelled() { 67 return cancelled; 68 } 69 70 protected final synchronized void resume() { 71 cancelled = false; 72 } 73 74 public final synchronized void cancel() { 75 cancelled = true; 76 } 77 78 public void run(CompilationInfo info) { 79 resume(); 80 81 if (isCancelled()) { 82 return; 83 } 84 85 Node root = AstUtilities.getRoot(info); 86 87 if (root == null) { 88 return; 89 } 90 91 Map <OffsetRange, ColoringAttributes> highlights = 92 new HashMap <OffsetRange, ColoringAttributes>(100); 93 94 AstPath path = new AstPath(); 95 path.descend(root); 96 annotate(root, highlights, path, null); 97 path.ascend(); 98 99 if (isCancelled()) { 100 return; 101 } 102 103 if (highlights.size() > 0) { 104 this.semanticHighlights = highlights; 105 } else { 106 this.semanticHighlights = null; 107 } 108 } 109 110 111 @SuppressWarnings ("unchecked") 112 private void annotate(Node node, Map <OffsetRange, ColoringAttributes> highlights, AstPath path, 113 List <String > parameters) { 114 if (node instanceof LocalAsgnNode) { 117 LocalAsgnNode lasgn = (LocalAsgnNode)node; 118 Node method = AstUtilities.findLocalScope(node, path); 119 120 boolean isUsed = isUsedInMethod(method, lasgn.getName()); 121 122 if (!isUsed) { 123 OffsetRange range = AstUtilities.getLValueRange(lasgn); 124 highlights.put(range, ColoringAttributes.UNUSED); 125 } else if (parameters != null) { 126 String name = ((LocalAsgnNode)node).getName(); 127 128 if (parameters.contains(name)) { 129 OffsetRange range = AstUtilities.getRange(node); 130 range = new OffsetRange(range.getStart(), range.getStart() + name.length()); 132 highlights.put(range, ColoringAttributes.PARAMETER); 133 } 134 } 135 } else if (node instanceof DAsgnNode) { 136 DAsgnNode dasgn = (DAsgnNode)node; 137 138 Node method = AstUtilities.findLocalScope(node, path); 139 140 boolean isUsed = isUsedInMethod(method, dasgn.getName()); 141 142 if (!isUsed) { 143 OffsetRange range = AstUtilities.getLValueRange(dasgn); 144 highlights.put(range, ColoringAttributes.UNUSED); 145 } 146 } else if (node instanceof DefnNode || node instanceof DefsNode) { 147 parameters = AstUtilities.getDefArgs(node); 148 149 if ((parameters != null) && (parameters.size() > 0)) { 150 List <String > unused = new ArrayList (); 151 152 for (String parameter : parameters) { 153 boolean isUsed = isUsedInMethod(node, parameter); 154 155 if (!isUsed) { 156 unused.add(parameter); 157 } 158 } 159 160 if (unused.size() > 0) { 161 annotateUnusedParameters(node, highlights, unused); 162 parameters.removeAll(unused); 163 } 164 165 if (parameters != null) { 166 if (parameters.size() == 0) { 167 parameters = null; 168 } else { 169 annotateParameters(node, highlights, parameters); 170 } 171 } 172 } 173 174 highlightMethodName(node, highlights); 175 } else if (node instanceof LocalVarNode) { 176 if (parameters != null) { 177 if (parameters.contains(((LocalVarNode)node).getName())) { 178 OffsetRange range = AstUtilities.getRange(node); 179 highlights.put(range, ColoringAttributes.PARAMETER); 180 } 181 } 182 } else if (node instanceof FCallNode || 183 node instanceof VCallNode ) { 184 OffsetRange range = AstUtilities.getCallRange(node); 186 highlights.put(range, ColoringAttributes.METHOD); 187 } 188 189 List <Node> list = node.childNodes(); 190 191 for (Node child : list) { 192 path.descend(child); 193 annotate(child, highlights, path, parameters); 194 path.ascend(); 195 } 196 } 197 198 @SuppressWarnings ("unchecked") 199 private void annotateParameters(Node node, Map <OffsetRange, ColoringAttributes> highlights, 200 List <String > usedParameterNames) { 201 List <Node> nodes = (List <Node>)node.childNodes(); 202 203 for (Node c : nodes) { 204 if (c instanceof ArgsNode) { 205 ArgsNode an = (ArgsNode)c; 206 207 if (an.getArgsCount() > 0) { 208 List <Node> args = (List <Node>)an.childNodes(); 209 210 for (Node arg : args) { 211 if (arg instanceof ListNode) { 212 List <Node> args2 = (List <Node>)arg.childNodes(); 213 214 for (Node arg2 : args2) { 215 if (arg2 instanceof ArgumentNode) { 216 if (usedParameterNames.contains(((ArgumentNode)arg2).getName())) { 217 OffsetRange range = AstUtilities.getRange(arg2); 218 highlights.put(range, ColoringAttributes.PARAMETER); 219 } 220 } else if (arg2 instanceof LocalAsgnNode) { 221 if (usedParameterNames.contains(((LocalAsgnNode)arg2).getName())) { 222 OffsetRange range = AstUtilities.getRange(arg2); 223 highlights.put(range, ColoringAttributes.PARAMETER); 224 } 225 } 226 } 227 } 228 } 229 } 230 } 231 } 232 } 233 234 @SuppressWarnings ("unchecked") 235 private void annotateUnusedParameters(Node node, 236 Map <OffsetRange, ColoringAttributes> highlights, List <String > names) { 237 List <Node> nodes = (List <Node>)node.childNodes(); 238 239 for (Node c : nodes) { 240 if (c instanceof ArgsNode) { 241 ArgsNode an = (ArgsNode)c; 242 243 if (an.getArgsCount() > 0) { 244 List <Node> args = (List <Node>)an.childNodes(); 245 246 for (Node arg : args) { 247 if (arg instanceof ListNode) { 248 List <Node> args2 = (List <Node>)arg.childNodes(); 249 250 for (Node arg2 : args2) { 251 if (arg2 instanceof ArgumentNode) { 252 if (names.contains(((ArgumentNode)arg2).getName())) { 253 OffsetRange range = AstUtilities.getRange(arg2); 254 highlights.put(range, ColoringAttributes.UNUSED); 255 } 256 } else if (arg2 instanceof LocalAsgnNode) { 257 if (names.contains(((LocalAsgnNode)arg2).getName())) { 258 OffsetRange range = AstUtilities.getRange(arg2); 259 highlights.put(range, ColoringAttributes.UNUSED); 260 } 261 } 262 } 263 } 264 } 265 } 266 } 267 } 268 } 269 270 @SuppressWarnings ("unchecked") 271 private boolean isUsedInMethod(Node node, String targetName) { 272 if (node instanceof LocalVarNode) { 273 String name = ((LocalVarNode)node).getName(); 274 275 if (targetName.equals(name)) { 276 return true; 277 } 278 } else if (node instanceof DVarNode) { 279 if (targetName.equals(((DVarNode)node).getName())) { 280 return true; 281 } 282 } else if (node instanceof AliasNode) { 283 AliasNode an = (AliasNode)node; 284 285 if (an.getOldName().equals(targetName)) { 286 return true; 287 } 288 } 289 290 List <Node> list = node.childNodes(); 291 292 for (Node child : list) { 293 if (child instanceof DefnNode || child instanceof DefsNode) { 297 continue; 298 } 299 300 boolean used = isUsedInMethod(child, targetName); 301 302 if (used) { 303 return true; 304 } 305 } 306 307 return false; 308 } 309 310 @SuppressWarnings ("unchecked") 311 private void highlightMethodName(Node node, Map <OffsetRange, ColoringAttributes> highlights) { 312 OffsetRange range = AstUtilities.getFunctionNameRange(node); 313 314 if (range != OffsetRange.NONE) { 315 if (!highlights.containsKey(range)) { highlights.put(range, ColoringAttributes.METHOD); 317 } 318 } 319 } 320 } 321 | Popular Tags |