Skip to content

Commit 8902ed1

Browse files
committed
Detect missing braces in tabs, ignore other problems until fixed
1 parent 25a2a59 commit 8902ed1

File tree

5 files changed

+146
-38
lines changed

5 files changed

+146
-38
lines changed

java/src/processing/mode/java/pdex/JavaProblem.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,28 @@ public class JavaProblem implements Problem {
6060

6161
public static final int ERROR = 1, WARNING = 2;
6262

63+
public JavaProblem(String message, int type, int tabIndex, int lineNumber) {
64+
this.message = message;
65+
this.type = type;
66+
this.tabIndex = tabIndex;
67+
this.lineNumber = lineNumber;
68+
}
69+
6370
/**
6471
*
6572
* @param iProblem - The IProblem which is being wrapped
6673
* @param tabIndex - The tab number to which the error belongs to
6774
* @param lineNumber - Line number(pde code) of the error
6875
*/
69-
public JavaProblem(IProblem iProblem, int tabIndex, int lineNumber) {
76+
public static JavaProblem fromIProblem(IProblem iProblem, int tabIndex, int lineNumber) {
77+
int type = 0;
7078
if(iProblem.isError()) {
7179
type = ERROR;
7280
} else if (iProblem.isWarning()) {
7381
type = WARNING;
7482
}
75-
this.tabIndex = tabIndex;
76-
this.lineNumber = lineNumber;
77-
this.message = ErrorMessageSimplifier.getSimplifiedErrorMessage(iProblem);
83+
String message = ErrorMessageSimplifier.getSimplifiedErrorMessage(iProblem);
84+
return new JavaProblem(message, type, tabIndex, lineNumber);
7885
}
7986

8087
public void setPDEOffsets(int startOffset, int stopOffset){

java/src/processing/mode/java/pdex/PDEX.java

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,40 +1079,69 @@ private void handleSketchProblems(PreprocessedSketch ps) {
10791079
Map<String, String[]> suggCache =
10801080
JavaMode.importSuggestEnabled ? new HashMap<>() : Collections.emptyMap();
10811081

1082-
// Process problems
1082+
final List<Problem> problems = new ArrayList<>();
1083+
10831084
IProblem[] iproblems = ps.compilationUnit.getProblems();
1084-
final List<Problem> problems = Arrays.stream(iproblems)
1085-
// Filter Warnings if they are not enabled
1086-
.filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled))
1087-
// Hide a useless error which is produced when a line ends with
1088-
// an identifier without a semicolon. "Missing a semicolon" is
1089-
// also produced and is preferred over this one.
1090-
// (Syntax error, insert ":: IdentifierOrNew" to complete Expression)
1091-
// See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780
1092-
.filter(iproblem -> !iproblem.getMessage()
1093-
.contains("Syntax error, insert \":: IdentifierOrNew\""))
1094-
// Transform into our Problems
1095-
.map(iproblem -> {
1096-
int start = iproblem.getSourceStart();
1097-
int stop = iproblem.getSourceEnd() + 1; // make it exclusive
1098-
SketchInterval in = ps.mapJavaToSketch(start, stop);
1099-
if (in == SketchInterval.BEFORE_START) return null;
1100-
int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);
1101-
JavaProblem p = new JavaProblem(iproblem, in.tabIndex, line);
1102-
p.setPDEOffsets(in.startTabOffset, in.stopTabOffset);
1103-
1104-
// Handle import suggestions
1105-
if (JavaMode.importSuggestEnabled && isUndefinedTypeProblem(iproblem)) {
1106-
ClassPath cp = ps.searchClassPath;
1107-
String[] s = suggCache.computeIfAbsent(iproblem.getArguments()[0],
1108-
name -> getImportSuggestions(cp, name));
1109-
p.setImportSuggestions(s);
1110-
}
11111085

1112-
return p;
1113-
})
1114-
.filter(Objects::nonNull)
1115-
.collect(Collectors.toList());
1086+
{ // Handle missing brace problems
1087+
IProblem missingBraceProblem = Arrays.stream(iproblems)
1088+
.filter(ErrorChecker::isMissingBraceProblem)
1089+
.findFirst()
1090+
// Ignore if it is at the end of file
1091+
.filter(p -> p.getSourceEnd() + 1 < ps.javaCode.length())
1092+
// Ignore if the tab number does not match our detected tab number
1093+
.filter(p -> ps.missingBraceProblems.isEmpty() ||
1094+
ps.missingBraceProblems.get(0).getTabIndex() ==
1095+
ps.mapJavaToSketch(p.getSourceStart(), p.getSourceEnd()+1).tabIndex
1096+
)
1097+
.orElse(null);
1098+
1099+
// If there is missing brace ignore all other problems
1100+
if (missingBraceProblem != null) {
1101+
// Prefer ECJ problem, shows location more accurately
1102+
iproblems = new IProblem[]{missingBraceProblem};
1103+
} else if (!ps.missingBraceProblems.isEmpty()) {
1104+
// Fallback to manual detection
1105+
problems.addAll(ps.missingBraceProblems);
1106+
}
1107+
}
1108+
1109+
if (problems.isEmpty()) {
1110+
List<Problem> cuProblems = Arrays.stream(iproblems)
1111+
// Filter Warnings if they are not enabled
1112+
.filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled))
1113+
// Hide a useless error which is produced when a line ends with
1114+
// an identifier without a semicolon. "Missing a semicolon" is
1115+
// also produced and is preferred over this one.
1116+
// (Syntax error, insert ":: IdentifierOrNew" to complete Expression)
1117+
// See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780
1118+
.filter(iproblem -> !iproblem.getMessage()
1119+
.contains("Syntax error, insert \":: IdentifierOrNew\""))
1120+
// Transform into our Problems
1121+
.map(iproblem -> {
1122+
int start = iproblem.getSourceStart();
1123+
int stop = iproblem.getSourceEnd() + 1; // make it exclusive
1124+
SketchInterval in = ps.mapJavaToSketch(start, stop);
1125+
if (in == SketchInterval.BEFORE_START) return null;
1126+
int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);
1127+
JavaProblem p = JavaProblem.fromIProblem(iproblem, in.tabIndex, line);
1128+
p.setPDEOffsets(in.startTabOffset, in.stopTabOffset);
1129+
1130+
// Handle import suggestions
1131+
if (JavaMode.importSuggestEnabled && isUndefinedTypeProblem(iproblem)) {
1132+
ClassPath cp = ps.searchClassPath;
1133+
String[] s = suggCache.computeIfAbsent(iproblem.getArguments()[0],
1134+
name -> getImportSuggestions(cp, name));
1135+
p.setImportSuggestions(s);
1136+
}
1137+
1138+
return p;
1139+
})
1140+
.filter(Objects::nonNull)
1141+
.collect(Collectors.toList());
1142+
1143+
problems.addAll(cuProblems);
1144+
}
11161145

11171146
if (scheduledUiUpdate != null) {
11181147
scheduledUiUpdate.cancel(true);
@@ -1129,13 +1158,28 @@ private void handleSketchProblems(PreprocessedSketch ps) {
11291158
}
11301159

11311160

1132-
private boolean isUndefinedTypeProblem(IProblem iproblem) {
1161+
static private boolean isUndefinedTypeProblem(IProblem iproblem) {
11331162
int id = iproblem.getID();
11341163
return id == IProblem.UndefinedType ||
11351164
id == IProblem.UndefinedName ||
11361165
id == IProblem.UnresolvedVariable;
11371166
}
11381167

1168+
static private boolean isMissingBraceProblem(IProblem iproblem) {
1169+
switch (iproblem.getID()) {
1170+
case IProblem.ParsingErrorInsertToComplete: {
1171+
char brace = iproblem.getArguments()[0].charAt(0);
1172+
return brace == '{' || brace == '}';
1173+
}
1174+
case IProblem.ParsingErrorInsertTokenAfter: {
1175+
char brace = iproblem.getArguments()[1].charAt(0);
1176+
return brace == '{' || brace == '}';
1177+
}
1178+
default:
1179+
return false;
1180+
}
1181+
}
1182+
11391183

11401184
public static String[] getImportSuggestions(ClassPath cp, String className) {
11411185
RegExpResourceFilter regf = new RegExpResourceFilter(

java/src/processing/mode/java/pdex/PreprocessedSketch.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.Collections;
1212
import java.util.List;
1313

14+
import processing.app.Problem;
1415
import processing.app.Sketch;
1516
import processing.core.PApplet;
1617
import processing.mode.java.pdex.TextTransform.OffsetMapper;
@@ -34,6 +35,8 @@ public class PreprocessedSketch {
3435

3536
public final OffsetMapper offsetMapper;
3637

38+
public final List<Problem> missingBraceProblems;
39+
3740
public final boolean hasSyntaxErrors;
3841
public final boolean hasCompilationErrors;
3942

@@ -212,6 +215,8 @@ public static class Builder {
212215

213216
public OffsetMapper offsetMapper;
214217

218+
public final List<Problem> missingBraceProblems = new ArrayList<>(0);
219+
215220
public boolean hasSyntaxErrors;
216221
public boolean hasCompilationErrors;
217222

@@ -246,6 +251,8 @@ private PreprocessedSketch(Builder b) {
246251

247252
offsetMapper = b.offsetMapper != null ? b.offsetMapper : OffsetMapper.EMPTY_MAPPER;
248253

254+
missingBraceProblems = Collections.unmodifiableList(b.missingBraceProblems);
255+
249256
hasSyntaxErrors = b.hasSyntaxErrors;
250257
hasCompilationErrors = b.hasCompilationErrors;
251258

java/src/processing/mode/java/pdex/PreprocessingService.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,15 @@ private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) {
392392
}
393393
}
394394

395+
{ // Check for missing braces
396+
List<JavaProblem> missingBraceProblems =
397+
SourceUtils.checkForMissingBraces(workBuffer, result.tabStartOffsets);
398+
if (!missingBraceProblems.isEmpty()) {
399+
result.missingBraceProblems.addAll(missingBraceProblems);
400+
result.hasSyntaxErrors = true;
401+
}
402+
}
403+
395404
// Transform code to parsable state
396405
String parsableStage = toParsable.apply();
397406
OffsetMapper parsableMapper = toParsable.getMapper();
@@ -414,7 +423,7 @@ private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) {
414423
makeAST(parser, compilableStageChars, COMPILER_OPTIONS);
415424

416425
// Get syntax problems from compilable AST
417-
result.hasSyntaxErrors = Arrays.stream(compilableCU.getProblems())
426+
result.hasSyntaxErrors |= Arrays.stream(compilableCU.getProblems())
418427
.anyMatch(IProblem::isError);
419428

420429
// Generate bindings after getting problems - avoids

java/src/processing/mode/java/pdex/SourceUtils.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,4 +323,45 @@ static public void scrubCommentsAndStrings(StringBuilder p) {
323323

324324
}
325325

326+
static public List<JavaProblem> checkForMissingBraces(StringBuilder p, int[] tabStartOffsets) {
327+
List<JavaProblem> problems = new ArrayList<>(0);
328+
tabLoop: for (int tabIndex = 0; tabIndex < tabStartOffsets.length; tabIndex++) {
329+
int tabStartOffset = tabStartOffsets[tabIndex];
330+
int tabEndOffset = (tabIndex < tabStartOffsets.length - 1) ?
331+
tabStartOffsets[tabIndex + 1] : p.length();
332+
int depth = 0;
333+
int lineNumber = 0;
334+
for (int i = tabStartOffset; i < tabEndOffset; i++) {
335+
char ch = p.charAt(i);
336+
switch (ch) {
337+
case '{':
338+
depth++;
339+
break;
340+
case '}':
341+
depth--;
342+
break;
343+
case '\n':
344+
lineNumber++;
345+
break;
346+
}
347+
if (depth < 0) {
348+
JavaProblem problem =
349+
new JavaProblem("Found one too many } characters without { to match it.",
350+
JavaProblem.ERROR, tabIndex, lineNumber);
351+
problem.setPDEOffsets(i - tabStartOffset, i - tabStartOffset + 1);
352+
problems.add(problem);
353+
continue tabLoop;
354+
}
355+
}
356+
if (depth > 0) {
357+
JavaProblem problem =
358+
new JavaProblem("Found one too many { characters without } to match it.",
359+
JavaProblem.ERROR, tabIndex, lineNumber - 1);
360+
problem.setPDEOffsets(tabEndOffset - tabStartOffset - 2, tabEndOffset - tabStartOffset - 1);
361+
problems.add(problem);
362+
}
363+
}
364+
return problems;
365+
}
366+
326367
}

0 commit comments

Comments
 (0)