mirror of
https://github.com/processing/processing4.git
synced 2026-02-02 21:29:17 +01:00
Gather error checking code in PDEX.ErrorChecker
This commit is contained in:
@@ -48,6 +48,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -1083,32 +1084,18 @@ public class PDEX {
|
||||
|
||||
IProblem[] iproblems = ps.compilationUnit.getProblems();
|
||||
|
||||
{ // 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
{ // Check for curly quotes
|
||||
List<JavaProblem> curlyQuoteProblems = checkForCurlyQuotes(ps);
|
||||
problems.addAll(curlyQuoteProblems);
|
||||
}
|
||||
|
||||
AtomicReference<ClassPath> searchClassPath = new AtomicReference<>(null);
|
||||
if (problems.isEmpty()) { // Check for missing braces
|
||||
List<JavaProblem> missingBraceProblems = checkForMissingBraces(ps);
|
||||
problems.addAll(missingBraceProblems);
|
||||
}
|
||||
|
||||
if (problems.isEmpty()) {
|
||||
AtomicReference<ClassPath> searchClassPath = new AtomicReference<>(null);
|
||||
List<Problem> cuProblems = Arrays.stream(iproblems)
|
||||
// Filter Warnings if they are not enabled
|
||||
.filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled))
|
||||
@@ -1121,17 +1108,10 @@ public class PDEX {
|
||||
.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;
|
||||
String badCode = ps.pdeCode.substring(in.startPdeOffset, in.stopPdeOffset);
|
||||
int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);
|
||||
JavaProblem p = JavaProblem.fromIProblem(iproblem, in.tabIndex, line, badCode);
|
||||
p.setPDEOffsets(in.startTabOffset, in.stopTabOffset);
|
||||
JavaProblem p = convertIProblem(iproblem, ps);
|
||||
|
||||
// Handle import suggestions
|
||||
if (JavaMode.importSuggestEnabled && isUndefinedTypeProblem(iproblem)) {
|
||||
if (p != null && JavaMode.importSuggestEnabled && isUndefinedTypeProblem(iproblem)) {
|
||||
ClassPath cp = searchClassPath.updateAndGet(prev -> prev != null ?
|
||||
prev : new ClassPathFactory().createFromPaths(ps.searchClassPathArray));
|
||||
String[] s = suggCache.computeIfAbsent(iproblem.getArguments()[0],
|
||||
@@ -1161,6 +1141,16 @@ public class PDEX {
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
static private JavaProblem convertIProblem(IProblem iproblem, PreprocessedSketch ps) {
|
||||
SketchInterval in = ps.mapJavaToSketch(iproblem);
|
||||
if (in == SketchInterval.BEFORE_START) return null;
|
||||
String badCode = ps.pdeCode.substring(in.startPdeOffset, in.stopPdeOffset);
|
||||
int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);
|
||||
JavaProblem p = JavaProblem.fromIProblem(iproblem, in.tabIndex, line, badCode);
|
||||
p.setPDEOffsets(in.startTabOffset, in.stopTabOffset);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static private boolean isUndefinedTypeProblem(IProblem iproblem) {
|
||||
int id = iproblem.getID();
|
||||
@@ -1186,6 +1176,119 @@ public class PDEX {
|
||||
}
|
||||
|
||||
|
||||
private static final Pattern CURLY_QUOTE_REGEX =
|
||||
Pattern.compile("([“”‘’])", Pattern.UNICODE_CHARACTER_CLASS);
|
||||
|
||||
static private List<JavaProblem> checkForCurlyQuotes(PreprocessedSketch ps) {
|
||||
List<JavaProblem> problems = new ArrayList<>(0);
|
||||
|
||||
// Go through the scrubbed code and look for curly quotes (they should not be any)
|
||||
Matcher matcher = CURLY_QUOTE_REGEX.matcher(ps.scrubbedPdeCode);
|
||||
while (matcher.find()) {
|
||||
int pdeOffset = matcher.start();
|
||||
String q = matcher.group();
|
||||
|
||||
int tabIndex = ps.pdeOffsetToTabIndex(pdeOffset);
|
||||
int tabOffset = ps.pdeOffsetToTabOffset(tabIndex, pdeOffset);
|
||||
int tabLine = ps.tabOffsetToTabLine(tabIndex, tabOffset);
|
||||
|
||||
String message = Language.interpolate("editor.status.bad_curly_quote", q);
|
||||
JavaProblem problem = new JavaProblem(message, JavaProblem.ERROR, tabIndex, tabLine, 10);
|
||||
problem.setPDEOffsets(tabOffset, tabOffset+1);
|
||||
|
||||
problems.add(problem);
|
||||
}
|
||||
|
||||
|
||||
// Go through iproblems and look for problems involving curly quotes
|
||||
List<JavaProblem> problems2 = new ArrayList<>(0);
|
||||
IProblem[] iproblems = ps.compilationUnit.getProblems();
|
||||
|
||||
for (IProblem iproblem : iproblems) {
|
||||
switch (iproblem.getID()) {
|
||||
case IProblem.ParsingErrorDeleteToken:
|
||||
case IProblem.ParsingErrorDeleteTokens:
|
||||
case IProblem.ParsingErrorInvalidToken:
|
||||
case IProblem.ParsingErrorReplaceTokens:
|
||||
case IProblem.UnterminatedString:
|
||||
SketchInterval in = ps.mapJavaToSketch(iproblem);
|
||||
if (in == SketchInterval.BEFORE_START) continue;
|
||||
String badCode = ps.pdeCode.substring(in.startPdeOffset, in.stopPdeOffset);
|
||||
matcher.reset(badCode);
|
||||
while (matcher.find()) {
|
||||
int offset = matcher.start();
|
||||
String q = matcher.group();
|
||||
int tabStart = in.startTabOffset + offset;
|
||||
int tabStop = tabStart + 1;
|
||||
// Prevent duplicate problems
|
||||
if (problems.stream().noneMatch(p -> p.getStartOffset() == tabStart)) {
|
||||
int line = ps.tabOffsetToTabLine(in.tabIndex, tabStart);
|
||||
String message;
|
||||
if (iproblem.getID() == IProblem.UnterminatedString) {
|
||||
message = Language.interpolate("editor.status.unterm_string_curly", q);
|
||||
} else {
|
||||
message = Language.interpolate("editor.status.bad_curly_quote", q);
|
||||
}
|
||||
JavaProblem p = new JavaProblem(message, JavaProblem.ERROR, in.tabIndex, line, 10);
|
||||
p.setPDEOffsets(tabStart, tabStop);
|
||||
problems2.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
problems.addAll(problems2);
|
||||
|
||||
return problems;
|
||||
}
|
||||
|
||||
|
||||
static private List<JavaProblem> checkForMissingBraces(PreprocessedSketch ps) {
|
||||
List<JavaProblem> problems = new ArrayList<>(0);
|
||||
for (int tabIndex = 0; tabIndex < ps.tabStartOffsets.length; tabIndex++) {
|
||||
int tabStartOffset = ps.tabStartOffsets[tabIndex];
|
||||
int tabEndOffset = (tabIndex < ps.tabStartOffsets.length - 1) ?
|
||||
ps.tabStartOffsets[tabIndex + 1] : ps.scrubbedPdeCode.length();
|
||||
int[] braceResult = SourceUtils.checkForMissingBraces(ps.scrubbedPdeCode, tabStartOffset, tabEndOffset);
|
||||
if (braceResult[0] != 0) {
|
||||
JavaProblem problem =
|
||||
new JavaProblem(braceResult[0] < 0
|
||||
? Language.interpolate("editor.status.missing.left_curly_bracket")
|
||||
: Language.interpolate("editor.status.missing.right_curly_bracket"),
|
||||
JavaProblem.ERROR, tabIndex, braceResult[1], 8);
|
||||
problem.setPDEOffsets(braceResult[3], braceResult[3] + 1);
|
||||
problems.add(problem);
|
||||
}
|
||||
}
|
||||
|
||||
if (problems.isEmpty()) {
|
||||
return problems;
|
||||
}
|
||||
|
||||
int problemTabIndex = problems.get(0).getTabIndex();
|
||||
|
||||
IProblem missingBraceProblem = Arrays.stream(ps.compilationUnit.getProblems())
|
||||
.filter(ErrorChecker::isMissingBraceProblem)
|
||||
// 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 -> problemTabIndex == ps.mapJavaToSketch(p).tabIndex)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
// Prefer ECJ problem, shows location more accurately
|
||||
if (missingBraceProblem != null) {
|
||||
JavaProblem p = convertIProblem(missingBraceProblem, ps);
|
||||
if (p != null) {
|
||||
problems.clear();
|
||||
problems.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
return problems;
|
||||
}
|
||||
|
||||
|
||||
static public String[] getImportSuggestions(ClassPath cp, String className) {
|
||||
RegExpResourceFilter regf = new RegExpResourceFilter(
|
||||
Pattern.compile(".*"),
|
||||
|
||||
@@ -2,6 +2,7 @@ package processing.mode.java.pdex;
|
||||
|
||||
import com.google.classpath.ClassPath;
|
||||
|
||||
import org.eclipse.jdt.core.compiler.IProblem;
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
|
||||
@@ -11,7 +12,6 @@ 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;
|
||||
@@ -30,13 +30,12 @@ public class PreprocessedSketch {
|
||||
|
||||
public final int[] tabStartOffsets;
|
||||
|
||||
public final String scrubbedPdeCode;
|
||||
public final String pdeCode;
|
||||
public final String javaCode;
|
||||
|
||||
public final OffsetMapper offsetMapper;
|
||||
|
||||
public final List<Problem> missingBraceProblems;
|
||||
|
||||
public final boolean hasSyntaxErrors;
|
||||
public final boolean hasCompilationErrors;
|
||||
|
||||
@@ -84,6 +83,12 @@ public class PreprocessedSketch {
|
||||
}
|
||||
|
||||
|
||||
public SketchInterval mapJavaToSketch(IProblem iproblem) {
|
||||
return mapJavaToSketch(iproblem.getSourceStart(),
|
||||
iproblem.getSourceEnd() + 1); // make it exclusive
|
||||
}
|
||||
|
||||
|
||||
public SketchInterval mapJavaToSketch(int startJavaOffset, int stopJavaOffset) {
|
||||
int length = stopJavaOffset - startJavaOffset;
|
||||
int startPdeOffset = javaOffsetToPdeOffset(startJavaOffset);
|
||||
@@ -120,7 +125,7 @@ public class PreprocessedSketch {
|
||||
}
|
||||
|
||||
|
||||
private int pdeOffsetToTabIndex(int pdeOffset) {
|
||||
public int pdeOffsetToTabIndex(int pdeOffset) {
|
||||
pdeOffset = Math.max(0, pdeOffset);
|
||||
int tab = Arrays.binarySearch(tabStartOffsets, pdeOffset);
|
||||
if (tab < 0) {
|
||||
@@ -130,7 +135,7 @@ public class PreprocessedSketch {
|
||||
}
|
||||
|
||||
|
||||
private int pdeOffsetToTabOffset(int tabIndex, int pdeOffset) {
|
||||
public int pdeOffsetToTabOffset(int tabIndex, int pdeOffset) {
|
||||
int tabStartOffset = tabStartOffsets[clipTabIndex(tabIndex)];
|
||||
return pdeOffset - tabStartOffset;
|
||||
}
|
||||
@@ -210,13 +215,12 @@ public class PreprocessedSketch {
|
||||
|
||||
public int[] tabStartOffsets = new int[0];
|
||||
|
||||
public String scrubbedPdeCode;
|
||||
public String pdeCode;
|
||||
public String javaCode;
|
||||
|
||||
public OffsetMapper offsetMapper;
|
||||
|
||||
public final List<Problem> missingBraceProblems = new ArrayList<>(0);
|
||||
|
||||
public boolean hasSyntaxErrors;
|
||||
public boolean hasCompilationErrors;
|
||||
|
||||
@@ -246,13 +250,12 @@ public class PreprocessedSketch {
|
||||
|
||||
tabStartOffsets = b.tabStartOffsets;
|
||||
|
||||
scrubbedPdeCode = b.scrubbedPdeCode;
|
||||
pdeCode = b.pdeCode;
|
||||
javaCode = b.javaCode;
|
||||
|
||||
offsetMapper = b.offsetMapper != null ? b.offsetMapper : OffsetMapper.EMPTY_MAPPER;
|
||||
|
||||
missingBraceProblems = Collections.unmodifiableList(b.missingBraceProblems);
|
||||
|
||||
hasSyntaxErrors = b.hasSyntaxErrors;
|
||||
hasCompilationErrors = b.hasCompilationErrors;
|
||||
|
||||
|
||||
@@ -312,6 +312,8 @@ public class PreprocessingService {
|
||||
|
||||
SourceUtils.scrubCommentsAndStrings(workBuffer);
|
||||
|
||||
result.scrubbedPdeCode = workBuffer.toString();
|
||||
|
||||
Mode sketchMode = PdePreprocessor.parseMode(workBuffer);
|
||||
|
||||
// Prepare transforms to convert pde code into parsable code
|
||||
@@ -394,15 +396,6 @@ 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();
|
||||
|
||||
@@ -331,27 +331,9 @@ public class SourceUtils {
|
||||
|
||||
}
|
||||
|
||||
static public List<JavaProblem> checkForMissingBraces(StringBuilder p, int[] tabStartOffsets) {
|
||||
List<JavaProblem> problems = new ArrayList<>(0);
|
||||
for (int tabIndex = 0; tabIndex < tabStartOffsets.length; tabIndex++) {
|
||||
int tabStartOffset = tabStartOffsets[tabIndex];
|
||||
int tabEndOffset = (tabIndex < tabStartOffsets.length - 1) ?
|
||||
tabStartOffsets[tabIndex + 1] : p.length();
|
||||
int[] braceResult = checkForMissingBraces(p, tabStartOffset, tabEndOffset);
|
||||
if (braceResult[0] != 0) {
|
||||
JavaProblem problem =
|
||||
new JavaProblem(braceResult[0] < 0
|
||||
? "Found one too many } characters without { to match it."
|
||||
: "Found one too many { characters without } to match it.",
|
||||
JavaProblem.ERROR, tabIndex, braceResult[1], 8);
|
||||
problem.setPDEOffsets(braceResult[3], braceResult[3] + 1);
|
||||
problems.add(problem);
|
||||
}
|
||||
}
|
||||
return problems;
|
||||
}
|
||||
|
||||
|
||||
// TODO: move this to a better place when JavaBuild starts using JDT and we
|
||||
// don't need to check errors at two different places [jv 2017-09-19]
|
||||
/**
|
||||
* Checks a single code fragment (such as a tab) for non-matching braces.
|
||||
* Broken out to allow easy use in JavaBuild.
|
||||
|
||||
Reference in New Issue
Block a user