Skip to content

Commit

Permalink
Fix for issue #302: ExpressionFinder sees comments in string literals
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Jun 6, 2017
1 parent 06cd163 commit bec328f
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 183 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2016 the original author or authors.
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -225,24 +225,24 @@ private GroovyClassLoader getLoaderFor(String path) {
return gcl;
}

public GroovyParser(CompilerOptions options, ProblemReporter problemReporter, boolean allowTransforms, boolean isReconcile) {
this(null, options, problemReporter, allowTransforms, isReconcile);
public GroovyParser(CompilerOptions compilerOptions, ProblemReporter problemReporter, boolean allowTransforms, boolean isReconcile) {
this(null, compilerOptions, problemReporter, allowTransforms, isReconcile);
}

public GroovyParser(Object requestor, CompilerOptions options, ProblemReporter problemReporter, boolean allowTransforms, boolean isReconcile) {
public GroovyParser(Object requestor, CompilerOptions compilerOptions, ProblemReporter problemReporter, boolean allowTransforms, boolean isReconcile) {
// FIXASC review callers who pass null for options
// FIXASC set parent of the loader to system or context class loader?

// record any paths we use for a project so that when the project is cleared,
// the paths (which point to cached classloaders) can be cleared

this.requestor = requestor;
this.compilerOptions = options;
this.compilerOptions = compilerOptions;
this.problemReporter = problemReporter;
this.projectName = options.groovyProjectName;
this.gclClasspath = (options == null ? null : options.groovyClassLoaderPath);
this.projectName = compilerOptions.groovyProjectName;
this.gclClasspath = compilerOptions.groovyClassLoaderPath;

GroovyClassLoader gcl = getLoaderFor(this.gclClasspath);
GroovyClassLoader gcl = getLoaderFor(gclClasspath);
// ---
// Status of transforms and reconciling: Oct-18-2011
// Prior to 2.6.0 all transforms were turned OFF for reconciling, and by turned off that meant no phase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,16 @@ final class TokenStreamTests {
doTest('foo[\'foo\']{ }', -1, BRACE_BLOCK, BRACK_BLOCK, IDENT, EOF)
}

@Test
void testBlockComment1() {
doTest('/* This is a block comment in a line */\n\'hello\'', -1, QUOTED_STRING, LINE_BREAK, BLOCK_COMMENT, EOF)
}

@Test
void testBlockComment2() {
doTest('/*\nThis is a block comment\n*/\n\'hello\'', -1, QUOTED_STRING, LINE_BREAK, BLOCK_COMMENT, EOF)
}

@Test
void testLineComment1() {
doTest('// This is a comment\n\'hello\'', -1, QUOTED_STRING, LINE_BREAK, LINE_COMMENT, EOF)
Expand All @@ -205,13 +215,8 @@ final class TokenStreamTests {
}

@Test
void testBlockComment1() {
doTest('/* This is a block comment in a line */\n\'hello\'', -1, QUOTED_STRING, LINE_BREAK, BLOCK_COMMENT, EOF)
}

@Test
void testBlockComment2() {
doTest('/*\nThis is a block comment\n*/\n\'hello\'', -1, QUOTED_STRING, LINE_BREAK, BLOCK_COMMENT, EOF)
void testFauxLineComment() {
doTest('"//";\nfrag', -1, IDENT, LINE_BREAK, SEMI, QUOTED_STRING, EOF)
}

@Test
Expand All @@ -234,43 +239,38 @@ final class TokenStreamTests {
doTest('foo.&bar', -1, IDENT, METHOD_POINTER, IDENT, EOF)
}

@Test
void testPeek() {
TokenStream stream = new TokenStream(new StringSourceBuffer('hello'), 4)
assert stream.peek().isType(IDENT)
}

@Test
void testLast() {
TokenStream stream = new TokenStream(new StringSourceBuffer('hello.'), 5)
Token next = stream.next()
assert stream.last() == next
assert stream.peek().isType(IDENT)
assert stream.last() == next
}

@Test(expected=TokenStreamException)
void testError1() throws Exception {
StringSourceBuffer sb = new StringSourceBuffer('0..1]')
TokenStream stream = new TokenStream(sb, '0..1]'.length() - 1)
TokenStream stream = new TokenStream(new StringSourceBuffer('0..1]'), 4)
stream.next()
}

@Test
void testOffsets1() {
// Don't mess with the dot's, the auto formatter eats spaces.
// ............0.........1.........2.........3
// ............0123456789012345678901234567890123456789
//.............0.........1.........2..
//.............01234567890123456789012
doTestOffsets('10.times { println it }', [9, 23, 3, 8, 2, 3, 0, 2] as int[])
}

@Test
void testOffsets2() {
// Don't mess with the dot's, the auto formatter eats spaces.
// ............0.........1.........2.........3
// ............0123456789012345678901234567890123456789
//.............0.........1.........2.........3
//.............0123456789012345678901234567890123456789
doTestOffsets('list[thing[i]].name', [15, 19, 14, 15, 4, 14, 0, 4] as int[])
}

@Test
void testPeek() {
StringSourceBuffer sb = new StringSourceBuffer('hello')
TokenStream stream = new TokenStream(sb, 'hello'.length() - 1)
assert stream.peek().isType(IDENT)
}

@Test
void testLast() {
StringSourceBuffer sb = new StringSourceBuffer('hello.')
TokenStream stream = new TokenStream(sb, 'hello.'.length() - 1)
Token next = stream.next()
assert stream.last() == next
assert stream.peek().isType(IDENT)
assert stream.last() == next
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2016 the original author or authors.
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,13 +15,15 @@
*/
package org.codehaus.groovy.eclipse.core.compiler;

import java.util.Hashtable;
import static org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies.proceedWithAllProblems;

import java.util.Iterator;
import java.util.Map;

import groovyjarjarasm.asm.Opcodes;
import org.codehaus.groovy.antlr.AntlrParserPlugin;
import org.codehaus.groovy.antlr.GroovySourceAST;
import org.codehaus.groovy.antlr.LocationSupport;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.ModuleNode;
Expand All @@ -33,121 +35,112 @@
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.groovy.core.util.ReflectionUtils;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;

/**
* @author Andrew Eisenberg
* @created Aug 11, 2009
*
* This class is used to parse a snippet of groovy source code into a module node
* The module node is not resolved
* This class is used to parse a snippet of groovy code into a module node.
* The module node is not resolved.
*/
public class GroovySnippetParser {

private static class MockCompilationUnit implements ICompilationUnit {

private char[] contents;
private char[] fileName;

MockCompilationUnit(char[] contents, char[] fileName) {
this.contents = contents;
this.fileName = fileName;
}

public char[] getContents() {
return contents;
}

public char[] getMainTypeName() {
return new char[0];
}

public char[][] getPackageName() {
return new char[0][];
}

public char[] getFileName() {
return fileName;
}

public boolean ignoreOptionalProblems() {
return false;
}
private LocationSupport locations;

public LocationSupport getLocations() {
return locations;
}

private CategorizedProblem[] problems;

public CategorizedProblem[] getProblems() {
return problems;
}

/**
* Compiles source code into a ModuleNode. Source code
* must be a complete file including package declaration
* and import statements.
*
* @param source the groovy source code to compile
*/
public ModuleNode parse(String source) {
Map<String, String> table = JavaCore.getOptions();
table.put(CompilerOptions.OPTIONG_BuildGroovyFiles, CompilerOptions.ENABLED);
CompilerOptions options = new CompilerOptions(table);
ProblemReporter reporter = new ProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(), options,
new DefaultProblemFactory());

GroovyParser parser = new GroovyParser(options, reporter, false, true);
ICompilationUnit unit = new MockCompilationUnit(source.toCharArray(), "Hello.groovy".toCharArray());
CompilationResult compilationResult = new CompilationResult(unit, 0, 0, options.maxProblemsPerUnit);


GroovyCompilationUnitDeclaration decl =
(GroovyCompilationUnitDeclaration)
parser.dietParse(unit, compilationResult);
ModuleNode node = decl.getModuleNode();

public ModuleNode parse(CharSequence source) {
ModuleNode node = dietParse(source).getModuleNode();
if (node == null) {
return null;
}
// Remove any remaining synthetic methods
for (ClassNode classNode : (Iterable<ClassNode>) node.getClasses()) {
for (Iterator<MethodNode> methodIter = classNode.getMethods().iterator(); methodIter.hasNext();) {
MethodNode method = methodIter.next();

// remove any remaining synthetic methods
for (ClassNode classNode : node.getClasses()) {
for (Iterator<MethodNode> it = classNode.getMethods().iterator(); it.hasNext();) {
MethodNode method = it.next();
if ((method.getModifiers() & Opcodes.ACC_SYNTHETIC) != 0) {
methodIter.remove();
it.remove();
}
}
}

problems = compilationResult.getErrors();
return node;
}

public CategorizedProblem[] getProblems() {
return problems;
public GroovySourceAST parseForCST(CharSequence source) {
SourceUnit sourceUnit = dietParse(source).getSourceUnit();
ParserPlugin parserPlugin = (ParserPlugin) ReflectionUtils.getPrivateField(SourceUnit.class, "parserPlugin", sourceUnit);
if (parserPlugin instanceof AntlrParserPlugin) {
// TODO: This field is nulled out at the end of AntlrParserPlugin.buildAST
return (GroovySourceAST) ReflectionUtils.getPrivateField(AntlrParserPlugin.class, "ast", parserPlugin);
}
return null;
}

public GroovySourceAST parseForCST(String source) {
Hashtable<String, String> table = JavaCore.getOptions();
table.put(CompilerOptions.OPTIONG_BuildGroovyFiles, CompilerOptions.ENABLED);
CompilerOptions options = new CompilerOptions(table);
ProblemReporter reporter = new ProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(), options,
new DefaultProblemFactory());
//--------------------------------------------------------------------------

GroovyParser parser = new GroovyParser(null, reporter, false, true);
ICompilationUnit unit = new MockCompilationUnit(source.toCharArray(), "Hello.groovy".toCharArray());
CompilationResult compilationResult = new CompilationResult(unit, 0, 0, options.maxProblemsPerUnit);
private GroovyCompilationUnitDeclaration dietParse(CharSequence source) {
Map<String, String> options = JavaCore.getOptions();
options.put(CompilerOptions.OPTIONG_BuildGroovyFiles, CompilerOptions.ENABLED);
CompilerOptions compilerOptions = new CompilerOptions(options);
ProblemReporter problemReporter = new ProblemReporter(proceedWithAllProblems(), compilerOptions, new DefaultProblemFactory());

GroovyParser parser = new GroovyParser(compilerOptions, problemReporter, false, true);
ICompilationUnit unit = new MockCompilationUnit(source.toString().toCharArray(), "Snippet.groovy".toCharArray());
CompilationResult compilationResult = new CompilationResult(unit, 0, 0, compilerOptions.maxProblemsPerUnit);

GroovyCompilationUnitDeclaration decl =
(GroovyCompilationUnitDeclaration)
parser.dietParse(unit, compilationResult);
SourceUnit sourceUnit = decl.getSourceUnit();
ParserPlugin parserPlugin = (ParserPlugin) ReflectionUtils.getPrivateField(SourceUnit.class, "parserPlugin", sourceUnit);
if (parserPlugin instanceof AntlrParserPlugin) {
return (GroovySourceAST) ReflectionUtils.getPrivateField(AntlrParserPlugin.class, "ast", parserPlugin);
} else {
return null;
GroovyCompilationUnitDeclaration gcud = (GroovyCompilationUnitDeclaration) parser.dietParse(unit, compilationResult);
locations = (LocationSupport) ReflectionUtils.getPrivateField(AntlrParserPlugin.class, "locations",
ReflectionUtils.getPrivateField(SourceUnit.class, "parserPlugin", gcud.getSourceUnit()));
problems = compilationResult.getProblems();
return gcud;
}

private static class MockCompilationUnit implements ICompilationUnit {

private char[] contents;
private char[] fileName;

MockCompilationUnit(char[] contents, char[] fileName) {
this.contents = contents;
this.fileName = fileName;
}

public char[] getContents() {
return contents;
}

public char[] getFileName() {
return fileName;
}

public char[] getMainTypeName() {
return new char[0];
}

public char[][] getPackageName() {
return new char[0][];
}

public boolean ignoreOptionalProblems() {
return false;
}
}
}
Loading

0 comments on commit bec328f

Please sign in to comment.