@Test public void testComputeAllSymbols_interface() throws InterruptedException, ExecutionException, IOException { addFileToFolder(workspaceRoot, "my/folder", "ICoordinates.groovy", "interface ICoordinates {\n" + " abstract double getAt(int idx);\n" + "}\n"); parser.parseAllSymbols(); Map<URI, Set<SymbolInformation>> symbols = parser.getFileSymbols(); // The symbols will contain a lot of inherited and default fields and methods, so we just check to make sure it // contains our custom fields and methods. assertThat(mapHasSymbol(symbols, Optional.absent(), "ICoordinates", SymbolKind.Interface)).isTrue(); assertThat(mapHasSymbol(symbols, Optional.of("ICoordinates"), "getAt", SymbolKind.Method)).isTrue(); assertThat(mapHasSymbol(symbols, Optional.of("getAt"), "idx", SymbolKind.Variable)).isTrue(); }
GroovyWorkspaceCompiler.of(targetDirectory, workspaceRoot, changedFilesDirectory); TreeParser parser = GroovyTreeParser.of(compiler, workspaceRoot, new WorkspaceUriSupplier(workspaceRoot, changedFilesDirectory)); DefaultCompilerWrapper groovycWrapper = new DefaultCompilerWrapper(compiler, parser);
/** * Creates a new instance of GroovyTreeParser. * * @param unitSupplier * the supplier of compilation unit to be parsed * @param workspaceRoot * the directory to compile * @param workspaceUriSupplier * the provider use to resolve uris * @return the newly created GroovyTreeParser */ @SuppressFBWarnings("PT_FINAL_TYPE_RETURN") public static GroovyTreeParser of(Supplier<CompilationUnit> unitSupplier, Path workspaceRoot, UriSupplier workspaceUriSupplier) { checkNotNull(unitSupplier, "unitSupplier must not be null"); checkNotNull(workspaceRoot, "workspaceRoot must not be null"); checkNotNull(workspaceUriSupplier, "workspaceUriSupplier must not be null"); checkArgument(workspaceRoot.toFile().isDirectory(), "workspaceRoot must be a directory"); return new GroovyTreeParser(unitSupplier, workspaceRoot, workspaceUriSupplier); }
@Test public void testReferences_typeEnumOneLine() throws IOException { // edge case on one line File enumFile = addFileToFolder(workspaceRoot, "MyEnum.groovy", "enum MyEnum {ONE,TWO}\n"); File scriptFile = addFileToFolder(workspaceRoot, "MyScript.groovy", "MyEnum a\n\n"); parser.parseAllSymbols(); // Find one line enum correctly Set<Location> myEnumExpectedResult = Sets.newHashSet( createLocation(scriptFile.toPath(), Ranges.createRange(0, 0, 0, 6))); assertEquals(myEnumExpectedResult, parser.findReferences(createReferenceParams(enumFile.toURI(), 0, 6, false))); }
createSymbolInformation(clazz.getName(), getKind(clazz), GroovyLocations.createClassDefinitionLocation(sourceUri, clazz), Optional.fromNullable(clazz.getOuterClass()).transform(ClassNode::getName)); SymbolInformation symbol = getVariableSymbolInformation(clazz.getName(), sourceUri, field); newIndexer.addSymbol(sourceUri, symbol); if (classes.containsKey(field.getType().getName())) { .forEach(method -> parseMethod(newIndexer, sourceUri, clazz, classes, classFields, method)); }); variable -> { SymbolInformation symbol = getVariableSymbolInformation(scriptClass.getName(), sourceUri, variable); newIndexer.addSymbol(sourceUnit.getSource().getURI(), symbol); if (classes.containsKey(variable.getType().getName())) {
@Override public CompletionList getCompletion(URI uri, Position position) { return CompletionUtils.createCompletionListFromSymbols(getFileSymbols().get(uri)); }
@Test public void testGotoDefinition_multipleFiles() throws IOException { File dog = addFileToFolder(workspaceRoot, "mydogfolder", "Dog.groovy", "public class Dog {}\n"); File cat = addFileToFolder(workspaceRoot, "mycatfolder", "Cat.groovy", "public class Cat {\n" + " public static Dog dog = new Dog()\n" + " public static Dog foo() {\n" + " Dog newDog = new Dog()\n" + " foo()\n" + " return newDog\n" + " }\n" + "}\n"); parser.parseAllSymbols(); // Dog class Location expectedLocation = new Location(dog.toPath().toUri().toString(), Ranges.createRange(0, 0, 0, 19)); assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(1, 18))); assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(2, 18))); assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(3, 8))); assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(3, 25))); // newDog local variable expectedLocation = new Location(cat.toPath().toUri().toString(), Ranges.createRange(3, 11, 3, 17)); assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(5, 18))); // foo method // TODO(#124): make this more accurate expectedLocation = new Location(cat.toPath().toUri().toString(), Ranges.createRange(2, 3, 6, 4)); assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(4, 10))); }
private void parseMethod(Indexer newIndexer, URI sourceUri, ClassNode parent, Map<String, Location> classes, Map<String, FieldNode> classFields, MethodNode method) { SymbolInformation methodSymbol = createSymbolInformation(method.getName(), SymbolKind.Method, GroovyLocations.createLocation(sourceUri, method), Optional.of(parent.getName())); newIndexer.addSymbol(sourceUri, methodSymbol); // Method parameters method.getVariableScope().getDeclaredVariables().values().forEach(variable -> { SymbolInformation variableSymbol = getVariableSymbolInformation(method.getName(), sourceUri, variable); newIndexer.addSymbol(sourceUri, variableSymbol); if (classes.containsKey(variable.getType().getName())) { newIndexer.addReference(classes.get(variable.getType().getName()), GroovyLocations.createLocation(sourceUri, variable.getType())); } }); // Return type if (classes.containsKey(method.getReturnType().getName())) { newIndexer.addReference(classes.get(method.getReturnType().getName()), GroovyLocations.createLocation(sourceUri, method.getReturnType())); } // We only want to visit the method if its not generated if (Ranges.isValid(methodSymbol.getLocation().getRange())) { // Visit the method if (method.getCode() instanceof BlockStatement) { BlockStatement blockStatement = (BlockStatement) method.getCode(); blockStatement.visit(new MethodVisitor(newIndexer, sourceUri, parent, classes, classFields, Optional.of(method), workspaceUriSupplier)); } } }
+ " abstract double getAt(int idx);\n" + "}\n"); parser.parseAllSymbols(); Set<SymbolInformation> filteredSymbols = parser.getFilteredSymbols("Coordinates"); assertEquals(Sets.newHashSet(new SymbolInformation( "Coordinates", filteredSymbols = parser.getFilteredSymbols("Coordinates*"); assertEquals(Sets.newHashSet( new SymbolInformation( filteredSymbols = parser.getFilteredSymbols("Coordinates?"); assertEquals(NO_SYMBOLS, filteredSymbols); filteredSymbols = parser.getFilteredSymbols("*Coordinates*"); assertThat(filteredSymbols).containsExactlyInAnyOrder( new SymbolInformation( filteredSymbols = parser.getFilteredSymbols("Coordinates???"); assertEquals(Sets.newHashSet( new SymbolInformation( "Coordinates")), filteredSymbols); filteredSymbols = parser.getFilteredSymbols("Coordinates..."); assertEquals(NO_SYMBOLS, filteredSymbols); filteredSymbols = parser.getFilteredSymbols("*Coordinates...*"); assertEquals(NO_SYMBOLS, filteredSymbols);
@Override public Set<SymbolInformation> getFilteredSymbols(String query) { checkNotNull(query, "query must not be null"); Pattern pattern = getQueryPattern(query); return indexer.getFileSymbols().values().stream().flatMap(Collection::stream) .filter(symbol -> pattern.matcher(symbol.getName()).matches()) .collect(Collectors.toSet()); }
@Test public void testReferences_catchStatement() throws IOException { File file = addFileToFolder(workspaceRoot, "Coordinates.groovy", "class Foo extends Throwable{}\n" + "try {\n" + " println \"Hello\"" + "}\n catch (Foo e1) {\n" + " println e1\n" + "}\n"); parser.parseAllSymbols(); // Class Foo Set<Location> expectedReferences = Sets.newHashSet(createLocation(file.toPath(), Ranges.createRange(3, 8, 3, 11))); // Get references when providing definition position assertEquals(expectedReferences, parser.findReferences(createReferenceParams(file.toURI(), 0, 6, false))); // Get references when providing position of usage assertEquals(expectedReferences, parser.findReferences(createReferenceParams(file.toURI(), 3, 9, false))); // TODO(#125): add a symbol for the exception variables and test here. }
@Test public void testNotParsedYet() throws IOException { assertEquals(NO_SYMBOLS, parser.getFileSymbols().values().stream().flatMap(Collection::stream).collect(Collectors.toSet())); }
+ " }\n" + "}\n"); parser.parseAllSymbols(); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(1, 15)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(10, 10)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(10, 31)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(12, 12)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(14, 11)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(11, 15)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(13, 10)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(11, 23)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(12, 23)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(13, 23)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(14, 20)).get()); assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(15, 20)).get());
@Test public void testReferences_typeInnerClassOneLine() throws IOException { // edge case on one line File innerClass = addFileToFolder(workspaceRoot, "AandB.groovy", "public class A {public static class B {}\n" + "A a\n" + "B b\n" + "}\n"); parser.parseAllSymbols(); // Identify type A correctly Set<Location> typeAExpectedResult = Sets.newHashSet( createLocation(innerClass.toPath(), Ranges.createRange(1, 0, 1, 1))); assertEquals(typeAExpectedResult, parser.findReferences(createReferenceParams(innerClass.toURI(), 0, 6, false))); // Identify type B correctly Set<Location> typeBExpectedResult = Sets.newHashSet( createLocation(innerClass.toPath(), Ranges.createRange(2, 0, 2, 1))); assertEquals(typeBExpectedResult, parser.findReferences(createReferenceParams(innerClass.toURI(), 0, 17, false))); }
@Test public void testComputeAllSymbols_enum() throws InterruptedException, ExecutionException, IOException { addFileToFolder(workspaceRoot, "Type.groovy", "enum Type {\n" + " ONE, TWO, THREE\n" + "}\n"); parser.parseAllSymbols(); Map<URI, Set<SymbolInformation>> symbols = parser.getFileSymbols(); // The symbols will contain a lot of inherited and default fields and methods, so we just check to make sure it // contains our custom fields and methods. assertThat(mapHasSymbol(symbols, Optional.absent(), "Type", SymbolKind.Enum)).isTrue(); assertThat(mapHasSymbol(symbols, Optional.of("Type"), "ONE", SymbolKind.Field)).isTrue(); assertThat(mapHasSymbol(symbols, Optional.of("Type"), "TWO", SymbolKind.Field)).isTrue(); assertThat(mapHasSymbol(symbols, Optional.of("Type"), "THREE", SymbolKind.Field)).isTrue(); }
@Test public void testWorkspaceRootNotFolder() throws IOException { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("workspaceRoot must be a directory"); GroovyTreeParser.of(() -> null, tempFolder.newFile().toPath(), uriSupplier); }
+ " }\n" + "}\n"); parser.parseAllSymbols(); assertEquals(NO_REFERENCES, parser.findReferences(createReferenceParams(file.toURI(), 7, 0, false))); assertEquals(NO_REFERENCES, parser.findReferences(createReferenceParams(file.toURI(), 10, 2, false))); assertEquals(expectedResult, parser.findReferences(createReferenceParams(file.toURI(), 13, 9, false)));
@Test public void testComputeAllSymbols_script() throws InterruptedException, ExecutionException, IOException { addFileToFolder(workspaceRoot, "test.groovy", "def name = \"Natacha\"\n" + "def myMethod() {\n" + " def someString = \"Also in symbols\"\n" + " println \"Hello World\"\n" + "}\n" + "println name\n" + "myMethod()\n"); parser.parseAllSymbols(); Map<URI, Set<SymbolInformation>> symbols = parser.getFileSymbols(); assertThat(mapHasSymbol(symbols, Optional.of("test"), "myMethod", SymbolKind.Method)).isTrue(); assertThat(mapHasSymbol(symbols, Optional.of("test"), "name", SymbolKind.Variable)).isTrue(); assertThat(mapHasSymbol(symbols, Optional.of("myMethod"), "someString", SymbolKind.Variable)).isTrue(); }
@Before public void setup() throws IOException { workspaceRoot = tempFolder.newFolder(); Path changedOutput = tempFolder.newFolder().toPath(); Path target = tempFolder.newFolder().toPath(); uriSupplier = new WorkspaceUriSupplier(workspaceRoot.toPath(), changedOutput); parser = GroovyTreeParser.of(() -> { GroovyWorkspaceCompiler compiler = GroovyWorkspaceCompiler.of(target, workspaceRoot.toPath(), changedOutput); assertEquals(Sets.newHashSet(), compiler.compile(ImmutableSet.of())); return compiler.get(); }, workspaceRoot.toPath(), uriSupplier); }
@Test public void testReferences_typeFields() throws IOException { File dogFile = addFileToFolder(workspaceRoot, "Dog.groovy", "class Dog {\n" + " Cat friend1;\n" + " Cat friend2;\n" + " Cat bark(Cat enemy) {\n" + " Cat myCat\n" + " println \"Bark! \" + enemy.name\n" + " return friend1\n" + " }\n" + "}\n"); File catFile = addFileToFolder(workspaceRoot, "Cat.groovy", "class Cat {\n" + " public String name = \"Bobby\"\n" + "}\n"); parser.parseAllSymbols(); // Dog should have no references assertEquals(NO_REFERENCES, parser.findReferences(createReferenceParams(dogFile.toURI(), 0, 7, false))); Set<Location> expectedResult = Sets.newHashSet( createLocation(dogFile.toPath(), Ranges.createRange(1, 3, 1, 6)), createLocation(dogFile.toPath(), Ranges.createRange(2, 3, 2, 6)), createLocation(dogFile.toPath(), Ranges.createRange(3, 3, 3, 6)), createLocation(dogFile.toPath(), Ranges.createRange(3, 12, 3, 15)), createLocation(dogFile.toPath(), Ranges.createRange(4, 6, 4, 9))); assertEquals(expectedResult, parser.findReferences(createReferenceParams(catFile.toURI(), 0, 7, false))); }