in search of the prediction prep deadlock on OS X (might be related to #3741)

This commit is contained in:
Ben Fry
2015-09-16 10:33:35 -04:00
parent 13ea8d03b7
commit f71b180014
2 changed files with 208 additions and 199 deletions

View File

@@ -22,6 +22,7 @@ package processing.mode.java.pdex;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -753,7 +754,7 @@ public class ASTGenerator {
return null;
}
protected void trimCandidates(String newWord){
protected void trimCandidates(String newWord) {
ArrayList<CompletionCandidate> newCandidate = new ArrayList<CompletionCandidate>();
newWord = newWord.toLowerCase();
for (CompletionCandidate comp : candidates) {
@@ -764,12 +765,8 @@ public class ASTGenerator {
candidates = newCandidate;
}
/**
* List of CompletionCandidates
*/
protected ArrayList<CompletionCandidate> candidates;
protected List<CompletionCandidate> candidates;
protected String lastPredictedWord = " ";
//protected AtomicBoolean predictionsEnabled;
protected int predictionMinLength = 2;
@@ -784,6 +781,17 @@ public class ASTGenerator {
*/
public void preparePredictions(final String word, final int line,
final int lineStartNonWSOffset) {
// EventQueue.invokeLater(new Runnable() {
// public void run() {
// preparePredictions2(word, line, lineStartNonWSOffset);
// }
// });
// }
//
// public void preparePredictions2(final String word, final int line,
// final int lineStartNonWSOffset) {
// System.out.println(EventQueue.isDispatchThread() + " " + predictionOngoing.get() + " " + (!JavaMode.codeCompletionsEnabled) + " " + (word.length() < predictionMinLength));
// new Exception("preparing predictions " + EventQueue.isDispatchThread() + " " + predictionOngoing.get() + " " + (!JavaMode.codeCompletionsEnabled) + " " + (word.length() < predictionMinLength)).printStackTrace(System.out);
if (predictionOngoing.get()) return;
if (!JavaMode.codeCompletionsEnabled) return;
if (word.length() < predictionMinLength) return;
@@ -797,6 +805,7 @@ public class ASTGenerator {
return;
}
// presumably this was removed because the caller is running from a SwingWorker [fry]
// SwingWorker worker = new SwingWorker() {
//
// @Override
@@ -806,48 +815,48 @@ public class ASTGenerator {
//
// protected void done() {
// If the parsed code contains pde enhancements, take 'em out.
String word2 = ASTNodeWrapper.getJavaCode(word);
// If the parsed code contains pde enhancements, take 'em out.
String word2 = ASTNodeWrapper.getJavaCode(word);
//After typing 'arg.' all members of arg type are to be listed. This one is a flag for it
boolean noCompare = false;
if (word2.endsWith(".")) {
// return all matches
word2 = word2.substring(0, word2.length() - 1);
noCompare = true;
//After typing 'arg.' all members of arg type are to be listed. This one is a flag for it
boolean noCompare = false;
if (word2.endsWith(".")) {
// return all matches
word2 = word2.substring(0, word2.length() - 1);
noCompare = true;
}
if (word2.length() >= predictionMinLength && !noCompare
&& word2.length() > lastPredictedWord.length()) {
if (word2.startsWith(lastPredictedWord)) {
log(word + " starts with " + lastPredictedWord);
log("Don't recalc");
if (word2.contains(".")) {
int x = word2.lastIndexOf('.');
trimCandidates(word2.substring(x + 1));
} else {
trimCandidates(word2);
}
showPredictions(word);
lastPredictedWord = word2;
predictionOngoing.set(false);
return;
}
}
if (word2.length() >= predictionMinLength && !noCompare
&& word2.length() > lastPredictedWord.length()) {
if (word2.startsWith(lastPredictedWord)) {
log(word + " starts with " + lastPredictedWord);
log("Don't recalc");
if (word2.contains(".")) {
int x = word2.lastIndexOf('.');
trimCandidates(word2.substring(x + 1));
} else {
trimCandidates(word2);
}
showPredictions(word);
lastPredictedWord = word2;
predictionOngoing.set(false);
return;
}
}
int lineNumber = line;
// Adjust line number for tabbed sketches
if (errorCheckerService != null) {
editor = errorCheckerService.getEditor();
int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab());
if (codeIndex > 0)
for (int i = 0; i < codeIndex; i++) {
SketchCode sc = editor.getSketch().getCode(i);
int len = Util.countLines(sc.getProgram()) + 1;
lineNumber += len;
}
int lineNumber = line;
// Adjust line number for tabbed sketches
if (errorCheckerService != null) {
editor = errorCheckerService.getEditor();
int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab());
if (codeIndex > 0) {
for (int i = 0; i < codeIndex; i++) {
SketchCode sc = editor.getSketch().getCode(i);
int len = Util.countLines(sc.getProgram()) + 1;
lineNumber += len;
}
}
}
// Ensure that we're not inside a comment. TODO: Binary search
@@ -864,157 +873,150 @@ public class ASTGenerator {
}
}*/
// Now parse the expression into an ASTNode object
ASTNode nearestNode = null;
ASTParser parser = ASTParser.newParser(AST.JLS4);
parser.setKind(ASTParser.K_EXPRESSION);
parser.setSource(word2.toCharArray());
ASTNode testnode = parser.createAST(null);
//Base.loge("PREDICTION PARSER PROBLEMS: " + parser);
// Find closest ASTNode of the document to this word
Messages.loge("Typed: " + word2 + "|" + " temp Node type: " + testnode.getClass().getSimpleName());
if(testnode instanceof MethodInvocation){
MethodInvocation mi = (MethodInvocation)testnode;
log(mi.getName() + "," + mi.getExpression() + "," + mi.typeArguments().size());
}
// Now parse the expression into an ASTNode object
ASTNode nearestNode = null;
ASTParser parser = ASTParser.newParser(AST.JLS4);
parser.setKind(ASTParser.K_EXPRESSION);
parser.setSource(word2.toCharArray());
ASTNode testnode = parser.createAST(null);
//Base.loge("PREDICTION PARSER PROBLEMS: " + parser);
// Find closest ASTNode of the document to this word
Messages.loge("Typed: " + word2 + "|" + " temp Node type: " + testnode.getClass().getSimpleName());
if(testnode instanceof MethodInvocation){
MethodInvocation mi = (MethodInvocation)testnode;
log(mi.getName() + "," + mi.getExpression() + "," + mi.typeArguments().size());
}
// find nearest ASTNode
nearestNode = findClosestNode(lineNumber, (ASTNode) errorCheckerService.getLastCorrectCU().types()
.get(0));
if (nearestNode == null) {
// Make sure nearestNode is not NULL if couldn't find a closeset node
nearestNode = (ASTNode) errorCheckerService.getLastCorrectCU().types().get(0);
}
Messages.loge(lineNumber + " Nearest ASTNode to PRED "
+ getNodeAsString(nearestNode));
// find nearest ASTNode
nearestNode = findClosestNode(lineNumber, (ASTNode) errorCheckerService.getLastCorrectCU().types()
.get(0));
if (nearestNode == null) {
// Make sure nearestNode is not NULL if couldn't find a closeset node
nearestNode = (ASTNode) errorCheckerService.getLastCorrectCU().types().get(0);
}
Messages.loge(lineNumber + " Nearest ASTNode to PRED "
+ getNodeAsString(nearestNode));
candidates = new ArrayList<CompletionCandidate>();
lastPredictedWord = word2;
// Determine the expression typed
candidates = new ArrayList<CompletionCandidate>();
lastPredictedWord = word2;
// Determine the expression typed
if (testnode instanceof SimpleName && !noCompare) {
Messages.loge("One word expression " + getNodeAsString(testnode));
//==> Simple one word exprssion - so is just an identifier
if (testnode instanceof SimpleName && !noCompare) {
Messages.loge("One word expression " + getNodeAsString(testnode));
//==> Simple one word exprssion - so is just an identifier
// Bottom up traversal of the AST to look for possible definitions at
// higher levels.
//nearestNode = nearestNode.getParent();
while (nearestNode != null) {
// If the current class has a super class, look inside it for
// definitions.
if (nearestNode instanceof TypeDeclaration) {
TypeDeclaration td = (TypeDeclaration) nearestNode;
if (td.getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) != null) {
SimpleType st = (SimpleType) td.getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY);
log("Superclass " + st.getName());
ArrayList<CompletionCandidate> tempCandidates =
getMembersForType(st.getName().toString(), word2, noCompare, false);
for (CompletionCandidate can : tempCandidates) {
candidates.add(can);
}
//findDeclaration(st.getName())
}
// Bottom up traversal of the AST to look for possible definitions at
// higher levels.
//nearestNode = nearestNode.getParent();
while (nearestNode != null) {
// If the current class has a super class, look inside it for
// definitions.
if (nearestNode instanceof TypeDeclaration) {
TypeDeclaration td = (TypeDeclaration) nearestNode;
if (td.getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) != null) {
SimpleType st = (SimpleType) td.getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY);
log("Superclass " + st.getName());
ArrayList<CompletionCandidate> tempCandidates =
getMembersForType(st.getName().toString(), word2, noCompare, false);
for (CompletionCandidate can : tempCandidates) {
candidates.add(can);
}
List<StructuralPropertyDescriptor> sprops =
nearestNode.structuralPropertiesForType();
for (StructuralPropertyDescriptor sprop : sprops) {
ASTNode cnode = null;
if (!sprop.isChildListProperty()) {
if (nearestNode.getStructuralProperty(sprop) instanceof ASTNode) {
cnode = (ASTNode) nearestNode.getStructuralProperty(sprop);
CompletionCandidate[] types = checkForTypes(cnode);
if (types != null) {
for (int i = 0; i < types.length; i++) {
if (types[i].getElementName().toLowerCase().startsWith(word2.toLowerCase()))
candidates.add(types[i]);
}
}
}
} else {
// Childlist prop
List<ASTNode> nodelist = (List<ASTNode>)
nearestNode.getStructuralProperty(sprop);
for (ASTNode clnode : nodelist) {
CompletionCandidate[] types = checkForTypes(clnode);
if (types != null) {
for (int i = 0; i < types.length; i++) {
if (types[i].getElementName().toLowerCase().startsWith(word2.toLowerCase()))
candidates.add(types[i]);
}
}
}
}
}
nearestNode = nearestNode.getParent();
//findDeclaration(st.getName())
}
// We're seeing a simple name that's not defined locally or in
// the parent class. So most probably a pre-defined type.
log("Empty can. " + word2);
if (classPath != null) {
RegExpResourceFilter regExpResourceFilter;
regExpResourceFilter = new RegExpResourceFilter(Pattern.compile(".*"),
Pattern.compile(word2 + "[a-zA-Z_0-9]*.class",
Pattern.CASE_INSENSITIVE));
String[] resources = classPath.findResources("", regExpResourceFilter);
for (String matchedClass2 : resources) {
matchedClass2 = matchedClass2.replace('/', '.'); //package name
String matchedClass = matchedClass2.substring(0, matchedClass2.length() - 6);
int d = matchedClass.lastIndexOf('.');
if (ignorableImport(matchedClass,matchedClass.substring(d + 1))) {
continue;
}
List<StructuralPropertyDescriptor> sprops =
nearestNode.structuralPropertiesForType();
for (StructuralPropertyDescriptor sprop : sprops) {
ASTNode cnode = null;
if (!sprop.isChildListProperty()) {
if (nearestNode.getStructuralProperty(sprop) instanceof ASTNode) {
cnode = (ASTNode) nearestNode.getStructuralProperty(sprop);
CompletionCandidate[] types = checkForTypes(cnode);
if (types != null) {
for (int i = 0; i < types.length; i++) {
if (types[i].getElementName().toLowerCase().startsWith(word2.toLowerCase()))
candidates.add(types[i]);
}
}
}
} else {
// Childlist prop
List<ASTNode> nodelist =
(List<ASTNode>) nearestNode.getStructuralProperty(sprop);
for (ASTNode clnode : nodelist) {
CompletionCandidate[] types = checkForTypes(clnode);
if (types != null) {
for (int i = 0; i < types.length; i++) {
if (types[i].getElementName().toLowerCase().startsWith(word2.toLowerCase()))
candidates.add(types[i]);
}
}
matchedClass = matchedClass.substring(d + 1); //class name
candidates
.add(new CompletionCandidate(matchedClass, "<html>"
+ matchedClass + " : <font color=#777777>"
+ matchedClass2.substring(0, d) + "</font></html>",
matchedClass,
CompletionCandidate.PREDEF_CLASS)); // display package name in grey
//log("-> " + className);
}
}
}
nearestNode = nearestNode.getParent();
}
// We're seeing a simple name that's not defined locally or in
// the parent class. So most probably a pre-defined type.
log("Empty can. " + word2);
if (classPath != null) {
RegExpResourceFilter regExpResourceFilter =
new RegExpResourceFilter(Pattern.compile(".*"),
Pattern.compile(word2 + "[a-zA-Z_0-9]*.class",
Pattern.CASE_INSENSITIVE));
String[] resources = classPath.findResources("", regExpResourceFilter);
for (String matchedClass2 : resources) {
matchedClass2 = matchedClass2.replace('/', '.'); //package name
String matchedClass = matchedClass2.substring(0, matchedClass2.length() - 6);
int d = matchedClass.lastIndexOf('.');
if (!ignorableImport(matchedClass,matchedClass.substring(d + 1))) {
matchedClass = matchedClass.substring(d + 1); //class name
// display package name in grey
String html = "<html>" + matchedClass + " : <font color=#777777>" +
matchedClass2.substring(0, d) + "</font></html>";
candidates.add(new CompletionCandidate(matchedClass, html,
matchedClass,
CompletionCandidate.PREDEF_CLASS));
}
}
}
} else {
// ==> Complex expression of type blah.blah2().doIt,etc
// Have to resolve it by carefully traversing AST of testNode
Messages.loge("Complex expression " + getNodeAsString(testnode));
log("candidates empty");
ASTNode childExpr = getChildExpression(testnode);
log("Parent expression : " + getParentExpression(testnode));
log("Child expression : " + childExpr);
if (childExpr != null) {
if (!noCompare) {
log("Original testnode " + getNodeAsString(testnode));
testnode = getParentExpression(testnode);
log("Corrected testnode " + getNodeAsString(testnode));
}
ClassMember expr =
resolveExpression3rdParty(nearestNode, testnode, noCompare);
if (expr == null) {
log("Expr is null");
} else {
// ==> Complex expression of type blah.blah2().doIt,etc
// Have to resolve it by carefully traversing AST of testNode
Messages.loge("Complex expression " + getNodeAsString(testnode));
log("candidates empty");
ASTNode childExpr = getChildExpression(testnode);
log("Parent expression : " + getParentExpression(testnode));
log("Child expression : " + childExpr);
if (childExpr != null) {
if (!noCompare) {
log("Original testnode "
+ getNodeAsString(testnode));
testnode = getParentExpression(testnode);
log("Corrected testnode "
+ getNodeAsString(testnode));
}
ClassMember expr = resolveExpression3rdParty(nearestNode, testnode,
noCompare);
if (expr == null) {
log("Expr is null");
} else {
log("Expr is " + expr.toString());
candidates = getMembersForType(expr, childExpr.toString(),
noCompare, false);
}
}
else
{
log("ChildExpr is null");
}
log("Expr is " + expr.toString());
candidates = getMembersForType(expr, childExpr.toString(),
noCompare, false);
}
showPredictions(word);
predictionOngoing.set(false);
} else {
log("ChildExpr is null");
}
}
showPredictions(word);
predictionOngoing.set(false);
// }
// };
//
// worker.execute();
}
protected void showPredictions(final String word) {
if (sketchOutline != null && sketchOutline.isVisible()) {
// don't show completions when the outline is visible
@@ -3364,7 +3366,7 @@ public class ASTGenerator {
private TreeSet<String> ignoredImportSuggestions;
public void suggestImports(final String className){
if(ignoredImportSuggestions == null) {
if (ignoredImportSuggestions == null) {
ignoredImportSuggestions = new TreeSet<String>();
} else {
if(ignoredImportSuggestions.contains(className)) {
@@ -3372,18 +3374,17 @@ public class ASTGenerator {
return;
}
}
if(frmImportSuggest != null)
if(frmImportSuggest.isVisible())
return;
if (frmImportSuggest != null) {
if (frmImportSuggest.isVisible()) {
return;
}
}
log("Looking for class " + className);
RegExpResourceFilter regf = new RegExpResourceFilter(
Pattern.compile(".*"),
Pattern
.compile(className
+ ".class",
Pattern.CASE_INSENSITIVE));
String[] resources = classPath
.findResources("", regf);
RegExpResourceFilter regf =
new RegExpResourceFilter(Pattern.compile(".*"),
Pattern.compile(className + ".class",
Pattern.CASE_INSENSITIVE));
String[] resources = classPath.findResources("", regf);
ArrayList<String> candidates = new ArrayList<String>();
for (String res : resources) {
candidates.add(res);
@@ -3504,14 +3505,15 @@ public class ASTGenerator {
classList.setSelectedIndex(0);
frmImportSuggest.setVisible(true);
}
}
public void disposeAllWindows() {
disposeWindow(frmASTView, frameAutoComp, frmImportSuggest,
frmOccurenceList, frmRename);
}
public static void disposeWindow(JFrame... f) {
for (JFrame jFrame : f) {
if(jFrame != null)
@@ -3519,6 +3521,7 @@ public class ASTGenerator {
}
}
protected boolean ignorableImport(String impName, String fullClassName) {
for (ImportStatement impS : errorCheckerService.getProgramImports()) {
if (impName.toLowerCase().startsWith(impS.getPackageName().toLowerCase())) {
@@ -3555,6 +3558,7 @@ public class ASTGenerator {
return true;
}
public static boolean isAddableASTNode(ASTNode node) {
switch (node.getNodeType()) {
// case ASTNode.STRING_LITERAL:
@@ -3567,6 +3571,7 @@ public class ASTGenerator {
}
}
/**
* For any line or expression, finds the line start offset(java code).
* @param node
@@ -3584,6 +3589,7 @@ public class ASTGenerator {
return node.getStartPosition();
}
/**
* For any node, finds various offsets (java code).
*
@@ -3605,7 +3611,6 @@ public class ASTGenerator {
}
static protected String getNodeAsString(ASTNode node) {
if (node == null)
return "NULL";