package tide.syntaxtree;
import japa.parser.ast.body.*;
import japa.parser.ast.CompilationUnit;
import javaparser.*;
import javaparser.javacc_gen.*;
import tide.editor.*;
import tide.sources.*;
import snow.concurrent.*;
import snow.utils.gui.*;
import snow.utils.StringUtils;
import java.util.*;
import java.io.*;
/** Some collected functions acting on the whole tree or branches.
* (removing trailing spaces, parsing to see warnings...)
*/
public final class TreeFunctions
{
public static boolean detectSourcesWithoutTypeOfSameName = false;
public static boolean detectSourcesWithoutType = false;
private TreeFunctions()
{
}
/** Removes the tailing spaces at the end of the lines + trim the source.
* TODO: don't work on files opened in the editor ...
*/
public static void removeTailingSpaces(final List<SourceFile> sfs)
{
final ProgressModalDialog pmd = new ProgressModalDialog(MainEditorFrame.instance, "Removing unuseful spaces in "+sfs.size()+" sources", false);
pmd.setProgressBounds(sfs.size());
pmd.start();
Thread t = new Thread()
{
public void run()
{
long removed = 0;
try
{
MainEditorFrame.instance.outputPanels.selectToolsTab(true);
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendLine("Cleaning "+sfs.size()+" java files: removing tailing spaces\n");
int modifFiles = 0;
sfl: for(SourceFile s: sfs)
{
pmd.incrementProgress(1);
pmd.setProgressComment( s.getJavaName() );
if(pmd.getWasCancelled())
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nCleaning cancelled by user.\n");
break;
}
if(!s.isEditable()) // was look
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nNot editable source: "+s.getJavaName()+"\n");
continue sfl;
}
try
{
String src = s.getContent().trim();
String nsrc = StringUtils.removeLineTailSpaces(src);
int diff = src.length()-nsrc.length();
if(diff>0)
{
removed += diff;
modifFiles++;
if(MainEditorFrame.debug)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendLine(s.getJavaName()+":0: removed "+diff+" chars");
}
s.setCaretPositionToRemember(s.getCaretLinePosition(), s.getCaretColumnPosition());
s.setContentFromEditor(nsrc, true); // allow, because we are quick, we will "win" and write our version, some millis after another.
s.saveContentToFile();
}
}
catch(Exception e)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nCleaner ERROR\n"+s.getJavaName()+":0: "+e.getMessage()+"\n");
e.printStackTrace();
}
}
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append(""+removed+" characters removed in "+modifFiles+" file"+(modifFiles==1?"":"s"));
}
finally
{
pmd.closeDialog();
}
}
};
t.setName("Removing tailing spaces");
t.start();
}
/** Parses all files, searching for syntax problems and write them.
* REMARK: this allow us to see that the parse tree have NO memory leak !
* parsing 2500 files don't leaks !
*/
public static void parseAllToSearchForProblems(final List<SourceFile> sfs, final boolean onlyRawParse)
{
final ProgressModalDialog pmd = new ProgressModalDialog(MainEditorFrame.instance, "Parsing "+sfs.size()
+" sources with the CC parser of Sreenivasa Viswanadha", false);
pmd.setProgressBounds(sfs.size());
pmd.start();
Thread t = new Thread()
{
public void run()
{
try
{
long t0 = System.currentTimeMillis();
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.setText("Parsing "+sfs.size()+" java files\n");
MainEditorFrame.instance.outputPanels.selectToolsTab(false);
int w = 0;
int err = 0;
int exc = 0;
for(SourceFile s: sfs)
{
pmd.incrementProgress(1);
pmd.setProgressComment( s.getJavaName() );
if(pmd.getWasCancelled())
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParsing cancelled by user.");
break;
}
try
{
int[] wee = parse(s, onlyRawParse); //.getContent(), s.getJavaName(), s.javaFile);
w += wee[0];
err += wee[1];
exc += wee[2];
}
catch(Exception e)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nPARSER ERROR\n"+s.getJavaName()+": "+e.getMessage());
e.printStackTrace();
}
}
if(MainEditorFrame.debug)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\nTotal time = " + (System.currentTimeMillis()-t0) + " ms, ");
}
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\n"+w+" warnings.");
if(err>0)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError(" "+err+" errors.");
}
if(exc>0)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError(" "+exc+" exceptions.");
}
}
finally
{
pmd.closeDialog();
}
}
};
t.setName("Parse debug");
t.start();
}
/** Parses all files, searching for syntax problems and write them.
* REMARK: this allow us to see that the parse tree have NO memory leak !
* parsing 2500 files don't leaks !
*/
public static void parseAllToSearchForProblems2(final List<SourceFile> sfs, final boolean onlyRawParse)
{
final ProgressModalDialog pmd = new ProgressModalDialog(MainEditorFrame.instance, "Parsing "+sfs.size()
+" sources with the new CC parser of Jlio Vilmar Gesser (jgesser@gmail.com)", false);
pmd.setProgressBounds(sfs.size());
pmd.start();
Thread t = new Thread()
{
public void run()
{
try
{
long t0 = System.currentTimeMillis();
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.setText("Parsing "+sfs.size()+" java files\n");
MainEditorFrame.instance.outputPanels.selectToolsTab(false);
int w = 0, err=0, exc=0;
for(SourceFile s: sfs)
{
pmd.incrementProgress(1);
pmd.setProgressComment( s.getJavaName() );
if(pmd.getWasCancelled())
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParsing cancelled by user.");
break;
}
try
{
int[] wee = parse2(s, onlyRawParse); //.getContent(), s.getJavaName(), s.javaFile);
w += wee[0];
err += wee[1];
exc += wee[2];
}
catch(Exception e)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nPARSER ERROR\n"+s.getJavaName()+": "+e.getMessage());
e.printStackTrace();
}
}
//if(MainEditorFrame.debug)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\nTotal time = " + (System.currentTimeMillis()-t0) + " ms, ");
}
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\n"+w+" warnings.");
if(err>0)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError(" "+err+" errors.");
}
if(exc>0)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError(" "+exc+" exceptions.");
}
}
finally
{
pmd.closeDialog();
}
}
};
t.setName("Parse debug");
t.start();
}
/** The thread must be launched with start() after creation.
*/
public static Thread createDetectDependenciesThread(final List<SourceFile> sfs, final boolean writeOut)
{
// A safe swing call
final ProgressModalDialog[] pmd = new ProgressModalDialog[1];
new SwingSafeRunnable(new Runnable() { public void run() {
pmd[0] = new ProgressModalDialog(MainEditorFrame.instance, "Detecting dependencies of "+sfs.size()+" sources", false);
}}, true).run();
MainEditorFrame.debugOut("Detecting dependentcies of "+sfs.size()+" sources.");
pmd[0].setProgressBounds(sfs.size());
pmd[0].start();
Thread t = new Thread()
{
public void run()
{
try
{
long t0 = System.currentTimeMillis();
if(writeOut)
{
MainEditorFrame.instance.outputPanels.selectToolsTab(true);
}
/* debug
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("Detecting dependencies of "+sfs.size()+" java files");
if(sfs.size()>0 && sfs.size()<5)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendLine(": "+sfs);
}
else
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendLine("");
}*/
for(final SourceFile s: sfs)
{
pmd[0].incrementProgress(1);
pmd[0].setProgressComment( s.getJavaName() );
if(pmd[0].getWasCancelled())
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendErrorLine("Parsing cancelled by user.");
break;
}
try
{
DependenciesDetector.updateDependencies(s, writeOut);
//MainEditorFrame.debugOut("Updated: "+s.sourceFileDependencies);
}
catch(Exception e)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendErrorLine("PARSER ERROR\n"+s.getJavaName()+": "+e.getMessage());
e.printStackTrace();
}
}
if(MainEditorFrame.debug)
{
long dt = (System.currentTimeMillis()-t0);
if(dt>1000)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendLine("Total dependencies detecting time = " + dt + " ms for "+sfs.size()+" files");
}
}
}
finally
{
pmd[0].closeDialog();
}
}
};
t.setName("Dependencies detection");
return t;
}
/** ex: japa.parser.ParseException: Encountered "(" at line 116, column 43.
*/
private static int[] getLinColFromParserMess(String message)
{
int line = 0;
int pos = message.indexOf("line ");
if(pos>0)
{
int posE = message.indexOf(',', pos+5);
if(posE>0)
{
String ls = message.substring(pos+5, posE);
//System.out.println("Error node: ls="+ls);
try
{
line = Integer.parseInt(ls);
} catch(Exception ee) { }
}
}
int column = 0;
pos = message.indexOf("column ", pos);
if(pos>0)
{
int posE = message.indexOf('.', pos+7);
if(posE>0)
{
String ls = message.substring(pos+7, posE);
try
{
column = Integer.parseInt(ls);
} catch(Exception ee) { }
}
}
return new int[]{line,column};
}
/** @return the number of warnings.
* AST dev trick: search in the DumpVisitor to find out where the items araises...
*/
public static int[] parse2(FileItem f, boolean onlyRawParse)
{
int w = 0;
int err = 0;
int exc = 0;
//long t0 = System.currentTimeMillis();
try
{
// special case.
if(f.getJavaPartName().equals("package-info")) return new int[3];
StringReader sr = new StringReader(f.getContent());
CompilationUnit cu = japa.parser.JavaParser.parse(sr);
if(onlyRawParse) return new int[3]; // just to see if it is parsable
// System.out.println(""+ cu.pakage.toString());
String pan = cu.pakage != null ? cu.pakage.toString():"";
/* if(!f.getPackageName().equals(pan))
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+1+")");
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append(": bad package name '"+pan+"' should be '"
+f.getPackageName()+"'");
w++;
}*/
List<TypeDeclaration> types = cu.types;
//System.out.println(""+types);
if(types==null || types.isEmpty())
{
if(detectSourcesWithoutType)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+1+")");
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append(": no declared type");
w++;
}
}
else
{
boolean hasNamed = false;
for(TypeDeclaration ti : types)
{
//System.out.println("type: "+ti.name);
// ti is null when classes blocks have exceding ";" at end, as in 1.6 and 1.7 src.
if(detectSourcesWithoutTypeOfSameName && ti.name!=null && ti.name.equals(f.getJavaPartName()))
{
hasNamed = true;
}
//analyse(ti);
}
if(detectSourcesWithoutTypeOfSameName && !hasNamed)
{
w++;
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+1+")");
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append(": no type named '"+f.getJavaPartName()+"'");
}
}
}
catch(Error e) // REALLY ! Lexical error
{
int[] lc = getLinColFromParserMess(e.getMessage());
//MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParseerror: "+e.getMessage());
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendErrorLine("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+lc[0]+"): ERROR "+StringUtils.firstLine(e.getMessage()));
//e.printStackTrace();
err++;
}
catch(Exception e)
{
int[] lc = getLinColFromParserMess(e.getMessage());
//MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParseerror: "+e.getMessage());
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendErrorLine("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+lc[0]+"): "+StringUtils.firstLine(e.getMessage()));
//e.printStackTrace();
exc++;
}
return new int[]{w,err,exc};
}
@tide.annotations.Recurse
static void analyse(TypeDeclaration ti)
{
System.out.println("Visiting type "+ti.name);
JapaVisitor jv = new JapaVisitor();
ti.accept(jv, null); //??
for(BodyDeclaration mi : ti.members) // fields, methods, inner class,...
{
//System.out.println("mi:"+mi);
mi.accept(jv, null); //??
if(mi instanceof TypeDeclaration)
{
analyse((TypeDeclaration) mi);
}
}
}
/** @return the number of warnings.
*/
public static int[] parse(FileItem f, boolean onlyRawParse)
{
int w = 0;
int err = 0;
int exc = 0;
//long t0 = System.currentTimeMillis();
try
{
StringReader sr = new StringReader(f.getContent());
JavaParser pa = new JavaParser(sr);
pa.disable_tracing();
RAWSyntaxTree st = new RAWSyntaxTree(f.getJavaName());
pa.parserOutputProcessor = st;
pa.CompilationUnit();
if(onlyRawParse) return new int[3];
//System.out.println("\nJavaParser took " + (System.currentTimeMillis()-t0) + " ms for "+f);
final SimplifiedSyntaxTree2 sst = new SimplifiedSyntaxTree2(st.root, f.getJavaName());
TreeFunctions.searchForCommonProblems(sst, sst.root, f.getJavaName());
sst.callAtEndToMakeWarningsVisible();
w = sst.getWarningsCount();
if(w>0)
{
for(int i=0; i<w; i++)
{
WarningNode wn = sst.getWarningNodeAt(i);
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+wn.getStartLinCol()[0]+"): ");
if(wn.gravity==1)
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError(wn.toString());
}
else
{
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append(wn.toString());
}
}
}
//System.out.println(""+fileName +"\t" +(System.currentTimeMillis()-t0) + "");
//final DefaultTreeModel tm = new DefaultTreeModel(sst.root);
}
catch(Error e) // REALLY ! Lexical error
{
int[] lc = getLinColFromParserMess(e.getMessage());
//MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParseerror: "+e.getMessage());
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendErrorLine("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+lc[0]+"): ERROR "+StringUtils.firstLine(e.getMessage()));
//e.printStackTrace();
err++;
}
catch(Exception e)
{
int[] lc = getLinColFromParserMess(e.getMessage());
//MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParseerror: "+e.getMessage());
MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendErrorLine("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+lc[0]+"): "+StringUtils.firstLine(e.getMessage()));
//e.printStackTrace();
exc++;
}
return new int[]{w,err,exc};
}
/** Apply all searches for common known problems.
*/
public static void searchForCommonProblems(SimplifiedSyntaxTree2 sst, final ParserTreeNode root, String javaName)
{
ProblemsSearch.analyseFile(sst, javaName);
searchForCommonProblemsRecurse(sst, root);
}
private static void searchForCommonProblemsRecurse(SimplifiedSyntaxTree2 sst, final ParserTreeNode root)
{
for(int i=0; i<root.getChildCount(); i++)
{
final ParserTreeNode ci = root.getChildNodeAt(i);
if(ci instanceof ClassNode)
{
ProblemsSearch.analyseClass(sst, (ClassNode) ci);
}
// recursively look for errors
searchForCommonProblemsRecurse(sst, ci);
}
}
}
|