com.cflint.CFLint Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of CFLint Show documentation
Show all versions of CFLint Show documentation
A static code analysis tool for ColdFusion (in the spirit of FindBugs and Lint). With CFLint, you are able to analyze your ColdFusion code base for code violations.
package com.cflint;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.antlr.runtime.BitSet;
import org.antlr.v4.runtime.ANTLRErrorListener;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
import com.cflint.BugInfo.BugInfoBuilder;
import com.cflint.config.CFLintChainedConfig;
import com.cflint.config.CFLintConfig;
import com.cflint.config.CFLintConfiguration;
import com.cflint.config.CFLintPluginInfo;
import com.cflint.config.CFLintPluginInfo.PluginInfoRule;
import com.cflint.config.CFLintPluginInfo.PluginInfoRule.PluginMessage;
import com.cflint.config.ConfigUtils;
import com.cflint.exception.CFLintScanException;
import com.cflint.listeners.ScanProgressListener;
import com.cflint.plugins.CFLintScanner;
import com.cflint.plugins.CFLintSet;
import com.cflint.plugins.CFLintStructureListener;
import com.cflint.plugins.Context;
import com.cflint.plugins.Context.ContextMessage;
import com.cflint.plugins.Context.ContextType;
import com.cflint.plugins.core.CFScopes;
import com.cflint.plugins.exceptions.CFLintExceptionListener;
import com.cflint.plugins.exceptions.DefaultCFLintExceptionListener;
import com.cflint.tools.AllowedExtensionsLoader;
import com.cflint.tools.CFLintFilter;
import com.cflint.tools.CFMLTagInfo;
import com.cflint.tools.CommentReformatting;
import com.cflint.tools.FileUtil;
import com.cflint.tools.PrecedingCommentReader;
import com.cflint.tools.ScanningProgressMonitorLookAhead;
import cfml.CFSCRIPTLexer;
import cfml.CFSCRIPTParser;
import cfml.parsing.CFMLParser;
import cfml.parsing.CFMLSource;
import cfml.parsing.ParserTag;
import cfml.parsing.cfscript.CFArrayExpression;
import cfml.parsing.cfscript.CFAssignmentExpression;
import cfml.parsing.cfscript.CFExpression;
import cfml.parsing.cfscript.CFFullVarExpression;
import cfml.parsing.cfscript.CFFunctionExpression;
import cfml.parsing.cfscript.CFIdentifier;
import cfml.parsing.cfscript.CFLiteral;
import cfml.parsing.cfscript.CFMember;
import cfml.parsing.cfscript.CFNewExpression;
import cfml.parsing.cfscript.CFStatement;
import cfml.parsing.cfscript.CFStringExpression;
import cfml.parsing.cfscript.CFStructElementExpression;
import cfml.parsing.cfscript.CFTernaryExpression;
import cfml.parsing.cfscript.CFVarDeclExpression;
import cfml.parsing.cfscript.script.CFCase;
import cfml.parsing.cfscript.script.CFCatchStatement;
import cfml.parsing.cfscript.script.CFCompDeclStatement;
import cfml.parsing.cfscript.script.CFCompoundStatement;
import cfml.parsing.cfscript.script.CFExpressionStatement;
import cfml.parsing.cfscript.script.CFForInStatement;
import cfml.parsing.cfscript.script.CFForStatement;
import cfml.parsing.cfscript.script.CFFuncDeclStatement;
import cfml.parsing.cfscript.script.CFFunctionParameter;
import cfml.parsing.cfscript.script.CFIfStatement;
import cfml.parsing.cfscript.script.CFIncludeStatement;
import cfml.parsing.cfscript.script.CFPropertyStatement;
import cfml.parsing.cfscript.script.CFReturnStatement;
import cfml.parsing.cfscript.script.CFScriptStatement;
import cfml.parsing.cfscript.script.CFSwitchStatement;
import cfml.parsing.cfscript.script.CFTryCatchStatement;
import cfml.parsing.cfscript.script.CFWhileStatement;
import cfml.parsing.reporting.ArrayErrorListener;
import cfml.parsing.reporting.IErrorReporter;
import cfml.parsing.reporting.ParseException;
import net.htmlparser.jericho.Attribute;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.EndTag;
import net.htmlparser.jericho.Source;
public class CFLint implements IErrorReporter {
// constants
private static final String FILE_ERROR = "FILE_ERROR";
private static final String PARSE_ERROR = "PARSE_ERROR";
private static final String PLUGIN_ERROR = "PLUGIN_ERROR";
private static final String MISSING_SEMI = "MISSING_SEMI";
private static final String AVOID_EMPTY_FILES = "AVOID_EMPTY_FILES";
private static final String RESOURCE_BUNDLE_NAME = "com.cflint.cflint";
private CFMLTagInfo tagInfo;
private CFMLParser cfmlParser = new CFMLParser();
private StackHandler handler = new StackHandler();
private BugList bugs;
private final List extensions = new ArrayList<>();
private final List allowedExtensions = new ArrayList<>();
private boolean verbose = false;
private boolean logError = false;
private boolean quiet = false;
private boolean debug = false;
private boolean showProgress = false;
private boolean progressUsesThread = true;
private CFLintStats stats = new CFLintStats();
private final List scanProgressListeners = new ArrayList<>();
private final List exceptionListeners = new ArrayList<>();
private CFLintConfiguration configuration;
private int skipToPosition = 0;
private String currentFile = null;
private Element currentElement = null;
private boolean strictInclude;
private Set> processed = new HashSet<>();
// Stack to store include file depth to ensure no recursion
private final Stack includeFileStack = new Stack<>();
private int[] lineOffsets;
public CFLint(final CFLintConfiguration configFile) throws IOException {
final CFLintFilter filter = CFLintFilter.createFilter(verbose);
bugs = new BugList(filter);
cfmlParser.setErrorReporter(this);
tagInfo = new CFMLTagInfo(cfmlParser.getDictionary());
setConfiguration(configFile);
if (exceptionListeners.isEmpty()) {
addExceptionListener(new DefaultCFLintExceptionListener(bugs));
}
}
public void setConfiguration(final CFLintConfiguration configFile) throws IOException {
configuration = configFile == null ? new CFLintConfig() : configFile;
extensions.clear();
allowedExtensions.clear();
scanProgressListeners.clear();
exceptionListeners.clear();
processed.clear();
for (final PluginInfoRule ruleInfo : configuration.getRules()) {
addScanner(ConfigUtils.loadPlugin(ruleInfo));// TODO load them all
}
allowedExtensions.addAll(AllowedExtensionsLoader.init(RESOURCE_BUNDLE_NAME));
bugs.clearBugList();
}
@Deprecated
public CFLint(final CFLintConfiguration configuration, final CFLintScanner... bugsScanners) {
super();
this.configuration = configuration;
for (final CFLintScanner scanner : bugsScanners) {
extensions.add(scanner);
if (configuration != null) {
final PluginInfoRule ruleInfo = configuration.getRuleByClass(scanner.getClass());
if (ruleInfo != null) {
ruleInfo.setPluginInstance(scanner);
}
}
if (scanner instanceof CFLintSet) {
((CFLintSet) scanner).setCFLint(this);
}
}
CFLintFilter filter;
try {
filter = CFLintFilter.createFilter(verbose);
bugs = new BugList(filter);
} catch (final IOException e1) {
e1.printStackTrace();
}
if (exceptionListeners.isEmpty()) {
addExceptionListener(new DefaultCFLintExceptionListener(bugs));
}
allowedExtensions.addAll(AllowedExtensionsLoader.init(RESOURCE_BUNDLE_NAME));
cfmlParser.setErrorReporter(this);
tagInfo = new CFMLTagInfo(cfmlParser.getDictionary());
}
public CFLintStats getStats() {
return stats;
}
public void scan(final String folderName) {
if (showProgress) {
ScanningProgressMonitorLookAhead.createInstance(this, folderName, progressUsesThread).startPreScan();
}
final File starterFile = new File(folderName);
setupConfigAncestry(starterFile.getAbsoluteFile().getParentFile());
scan(starterFile);
fireClose();
}
public void setupConfigAncestry(File folder) {
final Stack configFiles = new Stack<>();
fileLoop: while (folder != null && folder.exists()) {
for (final File file : folder.listFiles()) {
if (file.getName().toLowerCase().startsWith(".cflintrc")) {
if (verbose) {
System.out.println("read config " + file);
}
try {
@SuppressWarnings("deprecation")
final CFLintConfig newConfig = file.getName().toLowerCase().endsWith(".xml")
? ConfigUtils.unmarshal(file, CFLintConfig.class)
: ConfigUtils.unmarshalJson(new FileInputStream(file), CFLintConfig.class);
configFiles.push(newConfig);
if (!newConfig.isInheritParent()) {
break fileLoop;
}
} catch (final Exception e) {
if (!quiet) {
System.err.println("Could not read config file " + file + ". Check for duplicates.");
}
}
}
}
folder = folder.getParentFile();
}
for (final CFLintConfig newConfig : configFiles) {
configuration = new CFLintChainedConfig(newConfig, configuration);
}
}
public void scan(final File folderOrFile) {
if (debug) {
System.out.println("Current file: " + folderOrFile.getAbsolutePath());
}
if (getBugs().getFileFilter() != null && !getBugs().getFileFilter().includeFile(folderOrFile)) {
return;
}
if (!folderOrFile.exists()) {
System.err.println("File " + folderOrFile + " does not exist.");
return;
}
if (folderOrFile.isDirectory()) {
if (verbose) {
if (folderOrFile.getName().startsWith("."))
{
System.out.println("Skipping folder and its children: " + folderOrFile.getAbsolutePath());
return;
}
}
final CFLintConfiguration saveConfig = configuration;
try {
for (final File file : folderOrFile.listFiles()) {
if (file.getName().toLowerCase().startsWith(".cflintrc")) {
try {
if (verbose) {
System.out.println("read config " + file);
}
@SuppressWarnings("deprecation")
final CFLintConfiguration newConfig = file.getName().toLowerCase().endsWith(".xml")
? ConfigUtils.unmarshal(file, CFLintConfig.class)
: ConfigUtils.unmarshalJson(new FileInputStream(file), CFLintConfig.class);
configuration = new CFLintChainedConfig(newConfig, configuration);
} catch (final Exception e) {
System.err.println("Could not read config file " + file);
}
}
}
for (final File file : folderOrFile.listFiles()) {
scan(file);
}
} finally {
configuration = saveConfig;
}
} else if (!folderOrFile.isHidden() && FileUtil.checkExtension(folderOrFile, allowedExtensions)) {
if (!debug && verbose) {
System.out.println("Current file: " + folderOrFile.getAbsolutePath());
}
final String src = FileUtil.loadFile(folderOrFile);
includeFileStack.clear();
try {
// Report number of lines in the source
stats.addFile(src == null || src.length() == 0 ? 0 : src.split("\\R").length + 1);
process(src, folderOrFile.getAbsolutePath());
} catch (final Exception e) {
printException(e);
if (logError) {
System.err.println("Logging Error: " + FILE_ERROR);
fireCFLintException(e, FILE_ERROR, folderOrFile.getAbsolutePath(), null, null, null, null);
}
}
}
}
protected void printException(final Exception e, final Element... elem) {
e.printStackTrace();
if (!quiet) {
if (elem != null && elem.length > 0 && elem[0] != null) {
final int line = elem[0].getSource().getRow(elem[0].getBegin());
System.err.println("Error in: " + shortSource(elem[0].getSource(), line) + " @ " + line + ":");
}
if (verbose) {
e.printStackTrace(System.err);
} else {
System.err.println("Error: \"" + e.getMessage() + "\" Location: " + (e.getStackTrace().length > 0 ? e.getStackTrace()[0] : "''"));
}
}
}
public void process(final String src, final String filename) throws CFLintScanException {
try{
fireStartedProcessing(filename);
lineOffsets = null;
if (src == null || src.trim().length() == 0) {
final Context context = new Context(filename, null, null, false, handler,configuration);
reportRule(null, null, context, null, new ContextMessage(AVOID_EMPTY_FILES, null));
} else {
lineOffsets = getLineOffsets(src.split("\n"));
final CFMLSource cfmlSource = new CFMLSource(src.contains(" in the tag hierarchy
*
* @param element
* The element to process
* @param msgcode
* The message code to check for
* @return true if the msgcode is disabled for the given element.
*/
protected boolean checkForDisabled(final Element element, final String msgcode) {
Element elem = element;
while (elem != null) {
final Element prevSibling = getPreviousSibling(elem);
if (prevSibling != null && prevSibling.getName().equals(CF.COMMENT)) {
final Pattern p = Pattern.compile(".*---\\s*CFLINT-DISABLE\\s+(.*)\\s*---.*");
final Matcher m = p.matcher(prevSibling.toString().toUpperCase().trim());
if (m.matches()) {
// No message codes in CFLINT-DISABLE
if (m.group(1).trim().length() == 0) {
if (verbose) {
System.out.println("Skipping disabled " + msgcode);
}
return true;
}
// check for matching message codes in CFLINT-DISABLE
for (String skipcode : m.group(1).split(",")) {
skipcode = skipcode.trim();
if (msgcode.equals(skipcode)) {
if (verbose) {
System.out.println("Skipping disabled " + msgcode);
}
return true;
}
}
}
}
elem = elem.getParentElement();
}
return false;
}
public void reportRule(final Element elem, final Object currentExpression, final Context context,
final CFLintScanner pluginParm, final ContextMessage msg) {
final Object expression = msg.getCfExpression() != null? msg.getCfExpression():currentExpression;
// If we are processing includes, do NOT report any errors
if (!includeFileStack.isEmpty()) {
return;
}
final String msgcode = msg.getMessageCode();
final String nameVar = msg.getVariable();
final CFLintScanner plugin = msg.getSource() == null ? pluginParm : msg.getSource();
if (checkForDisabled(elem, msgcode)) {
return;
}
if (configuration == null) {
throw new NullPointerException("Configuration is null");
}
PluginInfoRule ruleInfo;
if (MISSING_SEMI.equals(msgcode)) {
ruleInfo = new PluginInfoRule();
final PluginMessage msgInfo = new PluginMessage(MISSING_SEMI);
msgInfo.setMessageText("End of statement(;) expected after ${variable}");
msgInfo.setSeverity(Levels.ERROR);
ruleInfo.getMessages().add(msgInfo);
} else if (PLUGIN_ERROR.equals(msgcode)) {
ruleInfo = new PluginInfoRule();
final PluginMessage msgInfo = new PluginMessage(PLUGIN_ERROR);
msgInfo.setMessageText("Error in plugin: ${variable}");
msgInfo.setSeverity(Levels.ERROR);
ruleInfo.getMessages().add(msgInfo);
} else if (AVOID_EMPTY_FILES.equals(msgcode)) {
ruleInfo = new PluginInfoRule();
final PluginMessage msgInfo = new PluginMessage(AVOID_EMPTY_FILES);
msgInfo.setMessageText("CF file is empty: ${file}");
msgInfo.setSeverity(Levels.WARNING);
ruleInfo.getMessages().add(msgInfo);
} else if (PARSE_ERROR.equals(msgcode)) {
ruleInfo = new CFLintPluginInfo.PluginInfoRule();
final CFLintPluginInfo.PluginInfoRule.PluginMessage msgInfo = new CFLintPluginInfo.PluginInfoRule.PluginMessage(
PARSE_ERROR);
msgInfo.setMessageText("Unable to parse");
msgInfo.setSeverity(Levels.ERROR);
ruleInfo.getMessages().add(msgInfo);
} else {
if (plugin == null) {
throw new NullPointerException(
"Plugin not set. Plugin should be using addMessage(messageCode,variable,source) to report messages in parent contexts");
}
ruleInfo = configuration.getRuleForPlugin(plugin);
}
if (ruleInfo == null) {
throw new NullPointerException("Rule not found for " + plugin.getClass().getSimpleName());
}
final PluginMessage msgInfo = ruleInfo.getMessageByCode(msgcode);
if (msgInfo == null) {
throw new NullPointerException(
"Message definition not found for [" + msgcode + "] in " + plugin.getClass().getSimpleName());
}
final BugInfoBuilder bldr = new BugInfo.BugInfoBuilder().setMessageCode(msgcode).setVariable(nameVar)
.setFunction(context.getFunctionName()).setFilename(context.getFilename())
.setComponent(context.getComponentName());
bldr.setSeverity(msgInfo.getSeverity());
bldr.setMessage(msgInfo.getMessageText());
if (expression instanceof CFStatement) {
bldr.setExpression(((CFStatement) expression).Decompile(0));
} else if (expression instanceof CFScriptStatement) {
bldr.setExpression(((CFScriptStatement) expression).Decompile(0));
} else if (elem != null) {
bldr.setExpression(elem.toString().replaceAll("\r\n", "\n"));
}
bldr.setRuleParameters(ruleInfo.getParameters());
if (configuration.includes(ruleInfo.getMessageByCode(msgcode))
&& !configuration.excludes(ruleInfo.getMessageByCode(msgcode))) {
//A bit of a hack to fix the offset issue
//This could be handled better at the source where line and offset are calc'd.
int idxOffSet = 1;
try{
if(lineOffsets != null && msg.getLine()!=null && msg.getOffset() != null && msg.getOffset() >=lineOffsets[msg.getLine()] ){
idxOffSet=0;
}
}catch(ArrayIndexOutOfBoundsException e){}
if (expression instanceof CFExpression) {
final BugInfo bugInfo = bldr.build((CFExpression) expression, elem);
final Token token = ((CFExpression) expression).getToken();
if (!suppressed(bugInfo, token, context)) {
bugs.add(bugInfo);
}
//If the context expression is attached, use the context line and column
if( msg.getCfExpression() != null && msg.getCfExpression() != currentExpression){
if (msg.getLine() != null) {
bugInfo.setLine(msg.getLine());
if (msg.getOffset() != null) {
bugInfo.setOffset(msg.getOffset());
bugInfo.setColumn(msg.getOffset() - lineOffsets[msg.getLine() - idxOffSet]);
} else {
bugInfo.setOffset(lineOffsets != null ? lineOffsets[msg.getLine() - idxOffSet] : 0);
bugInfo.setColumn(0);
}
}
}
} else {
final BugInfo bug = bldr.build((CFScriptStatement) expression, elem);
if (msg.getLine() != null) {
bug.setLine(msg.getLine());
if (msg.getOffset() != null) {
bug.setOffset(msg.getOffset());
bug.setColumn(msg.getOffset() - lineOffsets[msg.getLine() - idxOffSet]);
} else {
bug.setOffset(lineOffsets != null ? lineOffsets[msg.getLine() - idxOffSet] : 0);
bug.setColumn(0);
}
bug.setLength(msg.getVariable() != null ? msg.getVariable().length() : 0);
}
if (!suppressed(bug, expression==null?null:((CFScriptStatement)expression).getToken(), context)) {
bugs.add(bug);
}
}
}
}
/*
* Look for a suppress comment on the same line. cflint:line - suppresses
* any messages on the same line cflint:MESSAGE_CODE - suppresses any
* message matching that code
*/
protected boolean suppressed(final BugInfo bugInfo, final Token token, final Context context) {
if (context == null || context.isSuppressed(bugInfo)) {
return true;
}
if(token == null){
return false;
}
final Iterable tokens = context.afterTokens(token);
for (final Token currentTok : tokens) {
if (debug) {
System.out.println(currentTok.toString());
}
if (currentTok.getLine() != token.getLine()) {
break;
}
if (currentTok.getChannel() == Token.HIDDEN_CHANNEL && currentTok.getType() == CFSCRIPTLexer.LINE_COMMENT) {
final String commentText = currentTok.getText().replaceFirst("^//\\s*", "").trim();
if (commentText.startsWith("cflint ")) {
final Pattern pattern = Pattern.compile("cflint\\s+ignore:([\\w,]+).*");
final Matcher matcher = pattern.matcher(commentText);
if (matcher.matches() && matcher.groupCount() > 0) {
final String ignoreCodes = matcher.group(1);
if ("line".equalsIgnoreCase(ignoreCodes)) {
return true;
}
for (final String ignoreCode : ignoreCodes.split(",\\s*")) {
if (ignoreCode.equals(bugInfo.getMessageCode())) {
return true;
}
}
}
}
}
}
return false;
}
public BugList getBugs() {
return bugs;
}
public List getAllowedExtensions() {
return allowedExtensions;
}
public void setAllowedExtensions(final List allowedExtensions) {
this.allowedExtensions.clear();
if(allowedExtensions != null){
this.allowedExtensions.addAll(allowedExtensions);
}
}
@Override
public void reportError(final String arg0) {
// Empty implementation
}
public void setVerbose(final boolean verbose) {
this.verbose = verbose;
}
public void setLogError(final boolean logError) {
this.logError = logError;
}
public void setQuiet(final boolean quiet) {
this.quiet = quiet;
}
public void setDebug(final boolean debug) {
this.debug = debug;
}
public void addScanProgressListener(final ScanProgressListener scanProgressListener) {
scanProgressListeners.add(scanProgressListener);
}
protected void fireStartedProcessing(final String srcidentifier) {
cfmlParser = new CFMLParser();
cfmlParser.setErrorReporter(this);
currentFile = srcidentifier;
currentElement = null;
for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) {
try {
structurePlugin.startFile(srcidentifier, bugs);
} catch (final Exception e) {
printException(e);
final Context context = new Context(currentFile, currentElement, null, true, null, null);
final ContextMessage cm = new ContextMessage(PARSE_ERROR, null, null, context.startLine());
reportRule(currentElement, null, context, null, cm);
}
}
for (final ScanProgressListener p : scanProgressListeners) {
p.startedProcessing(srcidentifier);
}
}
protected void fireFinishedProcessing(final String srcidentifier) {
for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) {
try {
structurePlugin.endFile(srcidentifier, bugs);
} catch (final Exception e) {
printException(e);
final Context context = new Context(currentFile, currentElement, null, true, null, null);
final ContextMessage cm = new ContextMessage(PARSE_ERROR, null, null, context.startLine());
reportRule(currentElement, null, context, null, cm);
}
}
for (final ScanProgressListener p : scanProgressListeners) {
p.finishedProcessing(srcidentifier);
}
processed.clear();
}
protected void fireClose() {
for (final ScanProgressListener p : scanProgressListeners) {
p.close();
}
}
public void addScanner(final CFLintScanner plugin) {
if (plugin != null) {
extensions.add(plugin);
if (plugin instanceof CFLintSet) {
((CFLintSet) plugin).setCFLint(this);
}
}
}
public List getScanners() {
return extensions;
}
public void addExceptionListener(final CFLintExceptionListener exceptionListener) {
exceptionListeners.add(exceptionListener);
}
protected void fireCFLintException(final Throwable e, final String messageCode, final String filename,
final Integer line, final Integer column, final String functionName, final String expression) {
for (final CFLintExceptionListener p : exceptionListeners) {
p.exceptionOccurred(e, messageCode, filename, line, column, functionName, expression);
}
}
public void setShowProgress(final boolean showProgress) {
this.showProgress = showProgress;
}
public void setProgressUsesThread(final boolean progressUsesThread) {
this.progressUsesThread = progressUsesThread;
}
@Override
public void syntaxError(final Recognizer, ?> recognizer, final Object offendingSymbol, int line,
int charPositionInLine, final String msg, final org.antlr.v4.runtime.RecognitionException re) {
String expression = null;
int offset = charPositionInLine;
int startLine = 0;
int startOffset = 0;
final Context context = new Context(currentFile, currentElement, null, true, null, null);
if (currentElement != null) {
startOffset = context.offset();
if(context.startLine() != 1) {
startLine = currentElement.getSource().getRow(startOffset) - 1;
}
}
if (offendingSymbol instanceof Token && re != null) {
// grab the first non-comment previous token, which is actually the cause of the syntax error theoretically
CommonTokenStream tokenStream = (CommonTokenStream)recognizer.getInputStream();
Token previousToken = tokenStream.get(re.getOffendingToken().getTokenIndex()-1);
if (previousToken != null) {
while(previousToken.getChannel() == Token.HIDDEN_CHANNEL && tokenStream.get(previousToken.getTokenIndex()-1) != null) {
previousToken = tokenStream.get(previousToken.getTokenIndex()-1);
}
line = previousToken.getLine();
offset = previousToken.getStopIndex();
expression = previousToken.getText();
} else {
expression = re.getOffendingToken().getText();
}
if (expression.length() > 50) {
expression = expression.substring(1, 40) + "...";
}
}
offset += startOffset;
line += startLine;
if (recognizer instanceof Parser && ((Parser) recognizer).isExpectedToken(CFSCRIPTParser.SEMICOLON)) {
final ContextMessage cm = new ContextMessage(MISSING_SEMI, expression, null, line, offset);
reportRule(currentElement, null, context, null, cm);
} else {
final ContextMessage cm = new ContextMessage(PARSE_ERROR, expression, null, line, offset);
reportRule(currentElement, null, context, null, cm);
}
}
@Override
public void reportAmbiguity(final Parser recognizer, final DFA dfa, final int startIndex, final int stopIndex,
final boolean exact, final java.util.BitSet ambigAlts, final ATNConfigSet configs) {
// Empty implementation
}
@Override
public void reportAttemptingFullContext(final Parser recognizer, final DFA dfa, final int startIndex,
final int stopIndex, final java.util.BitSet conflictingAlts, final ATNConfigSet configs) {
// Empty implementation
}
@Override
public void reportContextSensitivity(final Parser recognizer, final DFA dfa, final int startIndex,
final int stopIndex, final int prediction, final ATNConfigSet configs) {
// Empty implementation
}
@Override
public void reportError(final org.antlr.v4.runtime.RecognitionException re) {
// Empty implementation
}
@Override
public void reportError(final String[] tokenNames, final org.antlr.v4.runtime.RecognitionException re) {
// Empty implementation
}
@Override
public void reportError(final org.antlr.v4.runtime.IntStream input,
final org.antlr.v4.runtime.RecognitionException re, final BitSet follow) {
// Empty implementation
}
public void setStrictIncludes(final boolean strictInclude) {
this.strictInclude = strictInclude;
}
}