mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
Detect missing braces in tabs, ignore other problems until fixed
This commit is contained in:
@@ -60,21 +60,28 @@ public class JavaProblem implements Problem {
|
||||
|
||||
public static final int ERROR = 1, WARNING = 2;
|
||||
|
||||
public JavaProblem(String message, int type, int tabIndex, int lineNumber) {
|
||||
this.message = message;
|
||||
this.type = type;
|
||||
this.tabIndex = tabIndex;
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param iProblem - The IProblem which is being wrapped
|
||||
* @param tabIndex - The tab number to which the error belongs to
|
||||
* @param lineNumber - Line number(pde code) of the error
|
||||
*/
|
||||
public JavaProblem(IProblem iProblem, int tabIndex, int lineNumber) {
|
||||
public static JavaProblem fromIProblem(IProblem iProblem, int tabIndex, int lineNumber) {
|
||||
int type = 0;
|
||||
if(iProblem.isError()) {
|
||||
type = ERROR;
|
||||
} else if (iProblem.isWarning()) {
|
||||
type = WARNING;
|
||||
}
|
||||
this.tabIndex = tabIndex;
|
||||
this.lineNumber = lineNumber;
|
||||
this.message = ErrorMessageSimplifier.getSimplifiedErrorMessage(iProblem);
|
||||
String message = ErrorMessageSimplifier.getSimplifiedErrorMessage(iProblem);
|
||||
return new JavaProblem(message, type, tabIndex, lineNumber);
|
||||
}
|
||||
|
||||
public void setPDEOffsets(int startOffset, int stopOffset){
|
||||
|
||||
@@ -1079,40 +1079,69 @@ public class PDEX {
|
||||
Map<String, String[]> suggCache =
|
||||
JavaMode.importSuggestEnabled ? new HashMap<>() : Collections.emptyMap();
|
||||
|
||||
// Process problems
|
||||
final List<Problem> problems = new ArrayList<>();
|
||||
|
||||
IProblem[] iproblems = ps.compilationUnit.getProblems();
|
||||
final List<Problem> problems = Arrays.stream(iproblems)
|
||||
// Filter Warnings if they are not enabled
|
||||
.filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled))
|
||||
// Hide a useless error which is produced when a line ends with
|
||||
// an identifier without a semicolon. "Missing a semicolon" is
|
||||
// also produced and is preferred over this one.
|
||||
// (Syntax error, insert ":: IdentifierOrNew" to complete Expression)
|
||||
// See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780
|
||||
.filter(iproblem -> !iproblem.getMessage()
|
||||
.contains("Syntax error, insert \":: IdentifierOrNew\""))
|
||||
// Transform into our Problems
|
||||
.map(iproblem -> {
|
||||
int start = iproblem.getSourceStart();
|
||||
int stop = iproblem.getSourceEnd() + 1; // make it exclusive
|
||||
SketchInterval in = ps.mapJavaToSketch(start, stop);
|
||||
if (in == SketchInterval.BEFORE_START) return null;
|
||||
int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);
|
||||
JavaProblem p = new JavaProblem(iproblem, in.tabIndex, line);
|
||||
p.setPDEOffsets(in.startTabOffset, in.stopTabOffset);
|
||||
|
||||
// Handle import suggestions
|
||||
if (JavaMode.importSuggestEnabled && isUndefinedTypeProblem(iproblem)) {
|
||||
ClassPath cp = ps.searchClassPath;
|
||||
String[] s = suggCache.computeIfAbsent(iproblem.getArguments()[0],
|
||||
name -> getImportSuggestions(cp, name));
|
||||
p.setImportSuggestions(s);
|
||||
}
|
||||
{ // Handle missing brace problems
|
||||
IProblem missingBraceProblem = Arrays.stream(iproblems)
|
||||
.filter(ErrorChecker::isMissingBraceProblem)
|
||||
.findFirst()
|
||||
// Ignore if it is at the end of file
|
||||
.filter(p -> p.getSourceEnd() + 1 < ps.javaCode.length())
|
||||
// Ignore if the tab number does not match our detected tab number
|
||||
.filter(p -> ps.missingBraceProblems.isEmpty() ||
|
||||
ps.missingBraceProblems.get(0).getTabIndex() ==
|
||||
ps.mapJavaToSketch(p.getSourceStart(), p.getSourceEnd()+1).tabIndex
|
||||
)
|
||||
.orElse(null);
|
||||
|
||||
return p;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
// If there is missing brace ignore all other problems
|
||||
if (missingBraceProblem != null) {
|
||||
// Prefer ECJ problem, shows location more accurately
|
||||
iproblems = new IProblem[]{missingBraceProblem};
|
||||
} else if (!ps.missingBraceProblems.isEmpty()) {
|
||||
// Fallback to manual detection
|
||||
problems.addAll(ps.missingBraceProblems);
|
||||
}
|
||||
}
|
||||
|
||||
if (problems.isEmpty()) {
|
||||
List<Problem> cuProblems = Arrays.stream(iproblems)
|
||||
// Filter Warnings if they are not enabled
|
||||
.filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled))
|
||||
// Hide a useless error which is produced when a line ends with
|
||||
// an identifier without a semicolon. "Missing a semicolon" is
|
||||
// also produced and is preferred over this one.
|
||||
// (Syntax error, insert ":: IdentifierOrNew" to complete Expression)
|
||||
// See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780
|
||||
.filter(iproblem -> !iproblem.getMessage()
|
||||
.contains("Syntax error, insert \":: IdentifierOrNew\""))
|
||||
// Transform into our Problems
|
||||
.map(iproblem -> {
|
||||
int start = iproblem.getSourceStart();
|
||||
int stop = iproblem.getSourceEnd() + 1; // make it exclusive
|
||||
SketchInterval in = ps.mapJavaToSketch(start, stop);
|
||||
if (in == SketchInterval.BEFORE_START) return null;
|
||||
int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);
|
||||
JavaProblem p = JavaProblem.fromIProblem(iproblem, in.tabIndex, line);
|
||||
p.setPDEOffsets(in.startTabOffset, in.stopTabOffset);
|
||||
|
||||
// Handle import suggestions
|
||||
if (JavaMode.importSuggestEnabled && isUndefinedTypeProblem(iproblem)) {
|
||||
ClassPath cp = ps.searchClassPath;
|
||||
String[] s = suggCache.computeIfAbsent(iproblem.getArguments()[0],
|
||||
name -> getImportSuggestions(cp, name));
|
||||
p.setImportSuggestions(s);
|
||||
}
|
||||
|
||||
return p;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
problems.addAll(cuProblems);
|
||||
}
|
||||
|
||||
if (scheduledUiUpdate != null) {
|
||||
scheduledUiUpdate.cancel(true);
|
||||
@@ -1129,13 +1158,28 @@ public class PDEX {
|
||||
}
|
||||
|
||||
|
||||
private boolean isUndefinedTypeProblem(IProblem iproblem) {
|
||||
static private boolean isUndefinedTypeProblem(IProblem iproblem) {
|
||||
int id = iproblem.getID();
|
||||
return id == IProblem.UndefinedType ||
|
||||
id == IProblem.UndefinedName ||
|
||||
id == IProblem.UnresolvedVariable;
|
||||
}
|
||||
|
||||
static private boolean isMissingBraceProblem(IProblem iproblem) {
|
||||
switch (iproblem.getID()) {
|
||||
case IProblem.ParsingErrorInsertToComplete: {
|
||||
char brace = iproblem.getArguments()[0].charAt(0);
|
||||
return brace == '{' || brace == '}';
|
||||
}
|
||||
case IProblem.ParsingErrorInsertTokenAfter: {
|
||||
char brace = iproblem.getArguments()[1].charAt(0);
|
||||
return brace == '{' || brace == '}';
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String[] getImportSuggestions(ClassPath cp, String className) {
|
||||
RegExpResourceFilter regf = new RegExpResourceFilter(
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import processing.app.Problem;
|
||||
import processing.app.Sketch;
|
||||
import processing.core.PApplet;
|
||||
import processing.mode.java.pdex.TextTransform.OffsetMapper;
|
||||
@@ -34,6 +35,8 @@ public class PreprocessedSketch {
|
||||
|
||||
public final OffsetMapper offsetMapper;
|
||||
|
||||
public final List<Problem> missingBraceProblems;
|
||||
|
||||
public final boolean hasSyntaxErrors;
|
||||
public final boolean hasCompilationErrors;
|
||||
|
||||
@@ -212,6 +215,8 @@ public class PreprocessedSketch {
|
||||
|
||||
public OffsetMapper offsetMapper;
|
||||
|
||||
public final List<Problem> missingBraceProblems = new ArrayList<>(0);
|
||||
|
||||
public boolean hasSyntaxErrors;
|
||||
public boolean hasCompilationErrors;
|
||||
|
||||
@@ -246,6 +251,8 @@ public class PreprocessedSketch {
|
||||
|
||||
offsetMapper = b.offsetMapper != null ? b.offsetMapper : OffsetMapper.EMPTY_MAPPER;
|
||||
|
||||
missingBraceProblems = Collections.unmodifiableList(b.missingBraceProblems);
|
||||
|
||||
hasSyntaxErrors = b.hasSyntaxErrors;
|
||||
hasCompilationErrors = b.hasCompilationErrors;
|
||||
|
||||
|
||||
@@ -392,6 +392,15 @@ public class PreprocessingService {
|
||||
}
|
||||
}
|
||||
|
||||
{ // Check for missing braces
|
||||
List<JavaProblem> missingBraceProblems =
|
||||
SourceUtils.checkForMissingBraces(workBuffer, result.tabStartOffsets);
|
||||
if (!missingBraceProblems.isEmpty()) {
|
||||
result.missingBraceProblems.addAll(missingBraceProblems);
|
||||
result.hasSyntaxErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Transform code to parsable state
|
||||
String parsableStage = toParsable.apply();
|
||||
OffsetMapper parsableMapper = toParsable.getMapper();
|
||||
@@ -414,7 +423,7 @@ public class PreprocessingService {
|
||||
makeAST(parser, compilableStageChars, COMPILER_OPTIONS);
|
||||
|
||||
// Get syntax problems from compilable AST
|
||||
result.hasSyntaxErrors = Arrays.stream(compilableCU.getProblems())
|
||||
result.hasSyntaxErrors |= Arrays.stream(compilableCU.getProblems())
|
||||
.anyMatch(IProblem::isError);
|
||||
|
||||
// Generate bindings after getting problems - avoids
|
||||
|
||||
@@ -323,4 +323,45 @@ public class SourceUtils {
|
||||
|
||||
}
|
||||
|
||||
static public List<JavaProblem> checkForMissingBraces(StringBuilder p, int[] tabStartOffsets) {
|
||||
List<JavaProblem> problems = new ArrayList<>(0);
|
||||
tabLoop: for (int tabIndex = 0; tabIndex < tabStartOffsets.length; tabIndex++) {
|
||||
int tabStartOffset = tabStartOffsets[tabIndex];
|
||||
int tabEndOffset = (tabIndex < tabStartOffsets.length - 1) ?
|
||||
tabStartOffsets[tabIndex + 1] : p.length();
|
||||
int depth = 0;
|
||||
int lineNumber = 0;
|
||||
for (int i = tabStartOffset; i < tabEndOffset; i++) {
|
||||
char ch = p.charAt(i);
|
||||
switch (ch) {
|
||||
case '{':
|
||||
depth++;
|
||||
break;
|
||||
case '}':
|
||||
depth--;
|
||||
break;
|
||||
case '\n':
|
||||
lineNumber++;
|
||||
break;
|
||||
}
|
||||
if (depth < 0) {
|
||||
JavaProblem problem =
|
||||
new JavaProblem("Found one too many } characters without { to match it.",
|
||||
JavaProblem.ERROR, tabIndex, lineNumber);
|
||||
problem.setPDEOffsets(i - tabStartOffset, i - tabStartOffset + 1);
|
||||
problems.add(problem);
|
||||
continue tabLoop;
|
||||
}
|
||||
}
|
||||
if (depth > 0) {
|
||||
JavaProblem problem =
|
||||
new JavaProblem("Found one too many { characters without } to match it.",
|
||||
JavaProblem.ERROR, tabIndex, lineNumber - 1);
|
||||
problem.setPDEOffsets(tabEndOffset - tabStartOffset - 2, tabEndOffset - tabStartOffset - 1);
|
||||
problems.add(problem);
|
||||
}
|
||||
}
|
||||
return problems;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user