|
From: <caw...@us...> - 2006-08-15 11:41:02
|
Revision: 1569 Author: cawilliams Date: 2006-08-15 04:40:54 -0700 (Tue, 15 Aug 2006) ViewCVS: http://svn.sourceforge.net/rubyeclipse/?rev=1569&view=rev Log Message: ----------- Fix problems which were only getting marked as "Syntax Error" Made task for handling duplicate markers or lint visitor (builder creates a marker and so does reconciler) Added way to grab source code for a node Modified LintVistor to check source before marking some of the warnings Modified Paths: -------------- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyScriptProblemFinder.java trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/IMarkerManager.java trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/MarkerManager.java trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/RubyCodeAnalyzer.java trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/RubyLintVisitor.java Added Paths: ----------- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/NodeUtil.java Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyScriptProblemFinder.java =================================================================== --- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyScriptProblemFinder.java 2006-08-15 04:21:04 UTC (rev 1568) +++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyScriptProblemFinder.java 2006-08-15 11:40:54 UTC (rev 1569) @@ -3,6 +3,7 @@ */ package org.rubypeople.rdt.internal.core; +import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Iterator; @@ -34,7 +35,8 @@ String contents = new String(charContents); try { Node node = parser.parse((IFile) script.getUnderlyingResource(), new StringReader(contents)); - RubyLintVisitor visitor = new RubyLintVisitor(problemRequestor); + // FIXME We're double marking problems here. We create markers for them when we build, and then create temporary annotations when we reconcile. We need to "toss" out any duplicates generated here. + RubyLintVisitor visitor = new RubyLintVisitor(contents, problemRequestor); node.accept(visitor); } catch (SyntaxException e) { problemRequestor.acceptProblem(new Error(e.getPosition(), "Syntax Error")); Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/IMarkerManager.java =================================================================== --- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/IMarkerManager.java 2006-08-15 04:21:04 UTC (rev 1568) +++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/IMarkerManager.java 2006-08-15 11:40:54 UTC (rev 1569) @@ -21,6 +21,7 @@ public interface IMarkerManager { public void removeProblemsAndTasksFor(IResource resource); public void createSyntaxError(IFile file, SyntaxException e); + public void createError(IFile file, String message, int startLine, int startOffset, int endOffset); public void createTasks(IFile file, List tasks) throws CoreException; public void addWarning(IFile file, String message); public void addWarning(IFile file, String message, int startLine, int startOffset, int endOffset); Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/MarkerManager.java =================================================================== --- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/MarkerManager.java 2006-08-15 04:21:04 UTC (rev 1568) +++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/MarkerManager.java 2006-08-15 11:40:54 UTC (rev 1569) @@ -21,6 +21,7 @@ import org.rubypeople.rdt.internal.core.parser.MarkerUtility; import org.rubypeople.rdt.internal.core.parser.RdtPosition; import org.rubypeople.rdt.internal.core.parser.Warning; +import org.rubypeople.rdt.internal.core.parser.Error; class MarkerManager implements IMarkerManager { @@ -51,4 +52,9 @@ MarkerUtility.createProblemMarker(file, new Warning(new RdtPosition(startLine, startOffset, endOffset), message)); } + public void createError(IFile file, String message, int startLine, int startOffset, int endOffset) { + MarkerUtility.createProblemMarker(file, new Error(new RdtPosition(startLine, startOffset, endOffset), message)); + + } + } Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/RubyCodeAnalyzer.java =================================================================== --- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/RubyCodeAnalyzer.java 2006-08-15 04:21:04 UTC (rev 1568) +++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/RubyCodeAnalyzer.java 2006-08-15 11:40:54 UTC (rev 1569) @@ -12,6 +12,8 @@ package org.rubypeople.rdt.internal.core.builder; +import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; @@ -41,10 +43,13 @@ public void compileFile(IFile file) throws CoreException { Reader reader = new InputStreamReader(file.getContents()); + // XXX Make sure readContents isn't dropping end of line characters + // XXX Use a StringReader for the parser since we've already read it all in once before? + String contents = readContents(reader); markerManager.removeProblemsAndTasksFor(file); try { Node rootNode = parser.parse(file, reader); - RubyLintVisitor visitor = new RubyLintVisitor(new ProblemRequestorMarkerManager(file, markerManager)); + RubyLintVisitor visitor = new RubyLintVisitor(contents, new ProblemRequestorMarkerManager(file, markerManager)); rootNode.accept(visitor); indexUpdater.update(file, rootNode, true); } catch (SyntaxException e) { @@ -54,4 +59,21 @@ } } + private String readContents(Reader reader) { + try { + BufferedReader buff = new BufferedReader(reader); + StringBuffer str = new StringBuffer(); + String line; + while((line = buff.readLine()) != null) { + str.append(line); + str.append("\n"); + } + return str.toString(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return ""; + } + } + } \ No newline at end of file Added: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/NodeUtil.java =================================================================== --- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/NodeUtil.java (rev 0) +++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/NodeUtil.java 2006-08-15 11:40:54 UTC (rev 1569) @@ -0,0 +1,14 @@ +package org.rubypeople.rdt.internal.core.parser; + +import org.jruby.ast.Node; +import org.jruby.lexer.yacc.ISourcePosition; + +public class NodeUtil { + + private NodeUtil() {} + + public static String getSource(String contents, Node node) { + ISourcePosition pos = node.getPosition(); + return contents.substring(pos.getStartOffset(), pos.getEndOffset()); + } +} Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/RubyLintVisitor.java =================================================================== --- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/RubyLintVisitor.java 2006-08-15 04:21:04 UTC (rev 1568) +++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/parser/RubyLintVisitor.java 2006-08-15 11:40:54 UTC (rev 1569) @@ -1,143 +1,294 @@ package org.rubypeople.rdt.internal.core.parser; + + +import java.io.Reader; + import java.util.HashSet; + import java.util.Set; + + import org.jruby.ast.BlockNode; + import org.jruby.ast.CallNode; + import org.jruby.ast.ConstDeclNode; + import org.jruby.ast.DefnNode; + import org.jruby.ast.DefsNode; + import org.jruby.ast.FCallNode; + import org.jruby.ast.FalseNode; + import org.jruby.ast.IfNode; + import org.jruby.ast.IterNode; + import org.jruby.ast.NilNode; + import org.jruby.ast.Node; + import org.jruby.ast.ScopeNode; + import org.jruby.ast.TrueNode; + import org.jruby.ast.WhenNode; + import org.jruby.evaluator.Instruction; + import org.jruby.lexer.yacc.ISourcePosition; + import org.rubypeople.rdt.core.IProblemRequestor; + import org.rubypeople.rdt.core.RubyCore; + import org.rubypeople.rdt.core.parser.IProblem; + + public class RubyLintVisitor extends InOrderVisitor { + + private IProblemRequestor problemRequestor; + private Set assignedConstants; + private Set methodsCalled; - public RubyLintVisitor(IProblemRequestor problemRequestor) { + private String contents; + + + + public RubyLintVisitor(String contents, IProblemRequestor problemRequestor) { + this.problemRequestor = problemRequestor; + assignedConstants = new HashSet(); + methodsCalled = new HashSet(); + + this.contents = contents; + } + + public Instruction visitFCallNode(FCallNode iVisited) { + methodsCalled.add(iVisited.getName()); + return super.visitFCallNode(iVisited); + } + + public Instruction visitCallNode(CallNode iVisited) { + methodsCalled.add(iVisited.getName()); + return super.visitCallNode(iVisited); + } + + public Instruction visitIfNode(IfNode iVisited) { + Node condition = iVisited.getCondition(); + if (condition instanceof TrueNode) { + problemRequestor.acceptProblem(new Warning(iVisited.getPosition(), + "Condition is always true")); + } else if ((condition instanceof FalseNode) + || (condition instanceof NilNode)) { + problemRequestor.acceptProblem(new Warning(iVisited.getPosition(), + "Condition is always false")); + } - if (iVisited.getThenBody() == null) { + String source = NodeUtil.getSource(contents, iVisited); + + if (iVisited.getThenBody() == null && !source.contains("unless")) { + IProblem problem = createProblem( + RubyCore.COMPILER_PB_EMPTY_STATEMENT, iVisited + .getPosition(), "Empty Conditional Body"); + if (problem != null) problemRequestor.acceptProblem(problem); + } + return super.visitIfNode(iVisited); + } + + public Instruction visitWhenNode(WhenNode iVisited) { + if (iVisited.getBodyNode() == null) { + IProblem problem = createProblem( + RubyCore.COMPILER_PB_EMPTY_STATEMENT, iVisited + .getPosition(), "Empty When Body"); + if (problem != null) problemRequestor.acceptProblem(problem); + } + return super.visitWhenNode(iVisited); + } + + public Instruction visitBlockNode(BlockNode iVisited) { return super.visitBlockNode(iVisited); + } + + public Instruction visitIterNode(IterNode iVisited) { + if (iVisited.getBodyNode() == null) { + IProblem problem = createProblem( + RubyCore.COMPILER_PB_EMPTY_STATEMENT, iVisited + .getPosition(), "Empty Block"); + if (problem != null) problemRequestor.acceptProblem(problem); + } + return super.visitIterNode(iVisited); + } + + public Instruction visitDefnNode(DefnNode iVisited) { + // TODO Analyze method visibility. Create warning for uncalled private + // methods + ScopeNode scope = iVisited.getBodyNode(); + if (scope.getBodyNode() == null) { + IProblem problem = createProblem( + RubyCore.COMPILER_PB_EMPTY_STATEMENT, iVisited + .getPosition(), "Empty Method Definition"); + if (problem != null) problemRequestor.acceptProblem(problem); + } + return super.visitDefnNode(iVisited); + } + + public Instruction visitDefsNode(DefsNode iVisited) { + ScopeNode scope = iVisited.getBodyNode(); + if (scope.getBodyNode() == null) { + IProblem problem = createProblem( + RubyCore.COMPILER_PB_EMPTY_STATEMENT, iVisited + .getPosition(), "Empty Method Definition"); + if (problem != null) problemRequestor.acceptProblem(problem); + } + return super.visitDefsNode(iVisited); + } + + protected Instruction handleNode(Node visited) { + // System.out.println(visited.toString() + ", position -> " + // + visited.getPosition()); + return super.handleNode(visited); + } + + public Instruction visitConstDeclNode(ConstDeclNode iVisited) { + String name = iVisited.getName(); + if (assignedConstants.contains(name)) { + problemRequestor.acceptProblem(new Warning(iVisited.getPosition(), + "Reassignment of a constant")); + } else + assignedConstants.add(name); + return super.visitConstDeclNode(iVisited); + } + + private IProblem createProblem(String compilerOption, + ISourcePosition position, String message) { + String value = RubyCore.getOption(compilerOption); - if ((value == null) || value.equals(RubyCore.WARNING)) + + if (value == null) + + return new Error(position, message); + + if (value.equals(RubyCore.WARNING)) + return new Warning(position, message); + if (value.equals(RubyCore.ERROR)) + return new Error(position, message); + return null; + } + + } + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |