Skip to content

Commit

Permalink
Lots of documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
matozoid committed May 31, 2018
1 parent 9c1d95c commit daaeb29
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 63 deletions.
Expand Up @@ -12,7 +12,7 @@
public class ParserCollectionStrategyTest {

private final Path root = CodeGenerationUtils.mavenModuleRoot(ParserCollectionStrategyTest.class).resolve("").getParent();
private final ProjectRoot projectRoot = new CollectionContext(new ParserCollectionStrategy()).collect(root);
private final ProjectRoot projectRoot = new ParserCollectionStrategy().collect(root);

@Test
public void getSourceRoots() {
Expand Down
Expand Up @@ -4,10 +4,12 @@

/**
* Set the strategy to be applied for collecting files for the ProjectRoot.
* @deprecated use {@link CollectionStrategy} directly
*/
@Deprecated
public class CollectionContext {

private CollectionStrategy strategy;
private final CollectionStrategy strategy;

public CollectionContext(CollectionStrategy strategy) {
this.strategy = strategy;
Expand Down
Expand Up @@ -11,7 +11,8 @@
import java.util.Optional;

/**
* Defines a strategy to collect files for the ProjectRoot.
* A strategy for discovering the structure of a project.
* Implementations could read a pom.xml, a Gradle build file, a makefile...
*/
public interface CollectionStrategy {

Expand Down
Expand Up @@ -9,7 +9,12 @@
import static java.nio.file.FileVisitResult.*;

/**
* Strategy which collects all SourceRoots and returns them in a ProjectRoot object.
* A brute force {@link CollectionStrategy} for discovering a project structure.
* It will search through the given project root path for Java files,
* look at their package declarations, and figure out the root directories for those files.
* No project definition files like pom.xml or build.gradle are used.
* This strategy is crude, but can work for many cases.
* Note that any build artifacts will also be detected: jar files in target directories and so on.
*/
public class ParserCollectionStrategy implements CollectionStrategy {

Expand Down
Expand Up @@ -10,21 +10,24 @@
import java.util.concurrent.ConcurrentHashMap;

/**
* Find and to compile all files in a project folder, which results in a collection of SourceRoots.
* To populate the ProjectRoot, set the CollectionStrategy in the CollectionContext to collect the required files.
* The structure of a Java project directory.
* It was originally created specifically to quickly configure the symbol solver.
* You can use it as a general container for project information.
* <p/>A project has a root directory, and it has zero or more directories that contain source code.
* <p/>To create a ProjectRoot use a CollectionStrategy, or instantiate ProjectRoot yourself.
*/
public class ProjectRoot {

private final Path projectRoot;
private final Path root;
private final Map<Path, SourceRoot> cache = new ConcurrentHashMap<>();
private ParserConfiguration parserConfiguration = new ParserConfiguration();
private final ParserConfiguration parserConfiguration;

public ProjectRoot(Path projectRoot) {
this.projectRoot = projectRoot;
public ProjectRoot(Path root) {
this(root, new ParserConfiguration());
}

public ProjectRoot(Path projectRoot, ParserConfiguration parserConfiguration) {
this.projectRoot = projectRoot;
public ProjectRoot(Path root, ParserConfiguration parserConfiguration) {
this.root = root;
this.parserConfiguration = parserConfiguration;
}

Expand All @@ -40,7 +43,15 @@ public void addSourceRoot(Path path) {
cache.put(path, new SourceRoot(path).setParserConfiguration(parserConfiguration));
}

/**
* @deprecated use getRoot()
*/
@Deprecated
public Path getProjectRoot() {
return projectRoot;
return root;
}

public Path getRoot() {
return root;
}
}
Expand Up @@ -17,11 +17,13 @@
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;

/**
* This implementation of the SymbolResolver wraps the functionalities of the library to make them easily usable
* This implementation of the SymbolResolver wraps the functionality of the library to make them easily usable
* from JavaParser nodes.
*
* <p>
* An instance of this class should be created once and then injected in all the CompilationUnit for which we
* want to enable symbol resolution. To do so the method inject can be used.
* want to enable symbol resolution. To do so the method inject can be used, or you can use
* {@link com.github.javaparser.ParserConfiguration#setSymbolResolver(SymbolResolver)} and the parser will do the
* injection for you.
*
* @author Federico Tomassetti
*/
Expand All @@ -44,7 +46,7 @@ public void inject(CompilationUnit destination) {
@Override
public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
if (node instanceof MethodDeclaration) {
return resultClass.cast(new JavaParserMethodDeclaration((MethodDeclaration)node, typeSolver));
return resultClass.cast(new JavaParserMethodDeclaration((MethodDeclaration) node, typeSolver));
}
if (node instanceof ClassOrInterfaceDeclaration) {
ResolvedReferenceTypeDeclaration resolved = JavaParserFactory.toTypeDeclaration(node, typeSolver);
Expand All @@ -60,16 +62,16 @@ public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
}
if (node instanceof EnumConstantDeclaration) {
ResolvedEnumDeclaration enumDeclaration = node.findParent(EnumDeclaration.class).get().resolve().asEnum();
ResolvedEnumConstantDeclaration resolved = enumDeclaration.getEnumConstants().stream().filter(c -> ((JavaParserEnumConstantDeclaration)c).getWrappedNode() == node).findFirst().get();
ResolvedEnumConstantDeclaration resolved = enumDeclaration.getEnumConstants().stream().filter(c -> ((JavaParserEnumConstantDeclaration) c).getWrappedNode() == node).findFirst().get();
if (resultClass.isInstance(resolved)) {
return resultClass.cast(resolved);
}
}
if (node instanceof ConstructorDeclaration) {
ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration)node;
ClassOrInterfaceDeclaration classOrInterfaceDeclaration = (ClassOrInterfaceDeclaration)node.getParentNode().get();
ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) node;
ClassOrInterfaceDeclaration classOrInterfaceDeclaration = (ClassOrInterfaceDeclaration) node.getParentNode().get();
ResolvedClassDeclaration resolvedClass = resolveDeclaration(classOrInterfaceDeclaration, ResolvedClassDeclaration.class).asClass();
ResolvedConstructorDeclaration resolved = resolvedClass.getConstructors().stream().filter(c -> ((JavaParserConstructorDeclaration)c).getWrappedNode() == constructorDeclaration).findFirst().get();
ResolvedConstructorDeclaration resolved = resolvedClass.getConstructors().stream().filter(c -> ((JavaParserConstructorDeclaration) c).getWrappedNode() == constructorDeclaration).findFirst().get();
if (resultClass.isInstance(resolved)) {
return resultClass.cast(resolved);
}
Expand All @@ -82,13 +84,13 @@ public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
}
if (node instanceof AnnotationMemberDeclaration) {
ResolvedAnnotationDeclaration annotationDeclaration = node.findParent(AnnotationDeclaration.class).get().resolve();
ResolvedAnnotationMemberDeclaration resolved = annotationDeclaration.getAnnotationMembers().stream().filter(c -> ((JavaParserAnnotationMemberDeclaration)c).getWrappedNode() == node).findFirst().get();
ResolvedAnnotationMemberDeclaration resolved = annotationDeclaration.getAnnotationMembers().stream().filter(c -> ((JavaParserAnnotationMemberDeclaration) c).getWrappedNode() == node).findFirst().get();
if (resultClass.isInstance(resolved)) {
return resultClass.cast(resolved);
}
}
if (node instanceof FieldDeclaration) {
FieldDeclaration fieldDeclaration = (FieldDeclaration)node;
FieldDeclaration fieldDeclaration = (FieldDeclaration) node;
if (fieldDeclaration.getVariables().size() != 1) {
throw new RuntimeException("Cannot resolve a Field Declaration including multiple variable declarators. Resolve the single variable declarators");
}
Expand All @@ -98,13 +100,13 @@ public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
}
}
if (node instanceof VariableDeclarator) {
ResolvedFieldDeclaration resolved = new JavaParserFieldDeclaration((VariableDeclarator)node, typeSolver);
ResolvedFieldDeclaration resolved = new JavaParserFieldDeclaration((VariableDeclarator) node, typeSolver);
if (resultClass.isInstance(resolved)) {
return resultClass.cast(resolved);
}
}
if (node instanceof MethodCallExpr) {
SymbolReference<ResolvedMethodDeclaration> result = JavaParserFacade.get(typeSolver).solve((MethodCallExpr)node);
SymbolReference<ResolvedMethodDeclaration> result = JavaParserFacade.get(typeSolver).solve((MethodCallExpr) node);
if (result.isSolved()) {
if (resultClass.isInstance(result.getCorrespondingDeclaration())) {
return resultClass.cast(result.getCorrespondingDeclaration());
Expand Down Expand Up @@ -165,15 +167,15 @@ public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
}
if (node instanceof Parameter) {
if (ResolvedParameterDeclaration.class.equals(resultClass)) {
Parameter parameter = (Parameter)node;
Parameter parameter = (Parameter) node;
CallableDeclaration callableDeclaration = node.findParent(CallableDeclaration.class).get();
ResolvedMethodLikeDeclaration resolvedMethodLikeDeclaration;
if (callableDeclaration.isConstructorDeclaration()) {
resolvedMethodLikeDeclaration = callableDeclaration.asConstructorDeclaration().resolve();
} else {
resolvedMethodLikeDeclaration = callableDeclaration.asMethodDeclaration().resolve();
}
for (int i=0;i<resolvedMethodLikeDeclaration.getNumberOfParams();i++) {
for (int i = 0; i < resolvedMethodLikeDeclaration.getNumberOfParams(); i++) {
if (resolvedMethodLikeDeclaration.getParam(i).getName().equals(parameter.getNameAsString())) {
return resultClass.cast(resolvedMethodLikeDeclaration.getParam(i));
}
Expand Down
Expand Up @@ -25,6 +25,9 @@
import java.util.zip.ZipEntry;

/**
* Will let the symbol solver look inside an Android aar file while solving types.
* (It will look inside the contained classes.jar)
*
* @author Federico Tomassetti
*/
public class AarTypeSolver implements TypeSolver {
Expand Down
Expand Up @@ -25,6 +25,9 @@
import java.util.List;

/**
* A container for type solvers. All solving is done by the contained type solvers.
* This helps you when an API asks for a single type solver, but you need several.
*
* @author Federico Tomassetti
*/
public class CombinedTypeSolver implements TypeSolver {
Expand Down
Expand Up @@ -32,6 +32,8 @@
import java.util.jar.JarFile;

/**
* Will let the symbol solver look inside a jar file while solving types.
*
* @author Federico Tomassetti
*/
public class JarTypeSolver implements TypeSolver {
Expand Down Expand Up @@ -73,15 +75,10 @@ private File dumpToTempFile(InputStream inputStream) throws IOException {

byte[] buffer = new byte[8 * 1024];

try {
OutputStream output = new FileOutputStream(tempFile);
try {
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} finally {
output.close();
try (OutputStream output = new FileOutputStream(tempFile)) {
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} finally {
inputStream.close();
Expand All @@ -101,13 +98,13 @@ private void addPathToJar(String pathToJar) throws IOException {
throw new RuntimeException(e);
}
JarFile jarFile = new JarFile(pathToJar);
JarEntry entry = null;
JarEntry entry;
Enumeration<JarEntry> e = jarFile.entries();
while (e.hasMoreElements()) {
entry = e.nextElement();
if (entry != null && !entry.isDirectory() && entry.getName().endsWith(".class")) {
String name = entryPathToClassName(entry.getName());
classpathElements.put(name, new ClasspathElement(jarFile, entry, name));
classpathElements.put(name, new ClasspathElement(jarFile, entry));
}
}
}
Expand Down Expand Up @@ -159,12 +156,10 @@ public ResolvedReferenceTypeDeclaration solveType(String name) throws UnsolvedSy
private class ClasspathElement {
private JarFile jarFile;
private JarEntry entry;
private String path;

ClasspathElement(JarFile jarFile, JarEntry entry, String path) {
ClasspathElement(JarFile jarFile, JarEntry entry) {
this.jarFile = jarFile;
this.entry = entry;
this.path = path;
}

CtClass toCtClass() throws IOException {
Expand Down
Expand Up @@ -43,7 +43,7 @@
import static com.github.javaparser.Providers.provider;

/**
* Defines a directory containig source code that should be used for solving symbols.
* Defines a directory containing source code that should be used for solving symbols.
* The directory must correspond to the root package of the files within.
*
* @author Federico Tomassetti
Expand Down
Expand Up @@ -24,12 +24,21 @@
import java.util.Optional;

/**
* Uses reflection to resolve types.
* All classes on the classpath used to run your application will be found.
* No source code is available for the resolved types.
*
* @author Federico Tomassetti
*/
public class ReflectionTypeSolver implements TypeSolver {

private TypeSolver parent;

/**
* @param jreOnly if true, will only resolve types from the java or javax packages.
* This is an easy way to say "I need a JRE to solve classes, and the one that is currently running is fine."
* If false, will resolve any kind of type.
*/
public ReflectionTypeSolver(boolean jreOnly) {
this.jreOnly = jreOnly;
}
Expand Down
Expand Up @@ -18,7 +18,7 @@
import static java.nio.file.FileVisitResult.SKIP_SUBTREE;

/**
* Strategy which collects all SourceRoots and initialises the TypeSolver and returns the SourceRoots configured
* {@link CollectionStrategy} which collects all SourceRoots and initialises the TypeSolver and returns the SourceRoots configured
* with the TypeSolver in a ProjectRoot object.
*/
public class SymbolSolverCollectionStrategy implements CollectionStrategy {
Expand Down
@@ -1,42 +1,45 @@
package com.github.javaparser.symbolsolver.utils;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.utils.*;
import com.github.javaparser.utils.CodeGenerationUtils;
import com.github.javaparser.utils.Log;
import com.github.javaparser.utils.ProjectRoot;
import com.github.javaparser.utils.SourceRoot;
import org.junit.Test;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

import static org.junit.Assert.assertTrue;

public class SymbolSolverCollectionStrategyTest {

private final Path root = CodeGenerationUtils.mavenModuleRoot(SymbolSolverCollectionStrategyTest.class).resolve("").getParent();
private final ProjectRoot projectRoot = new CollectionContext(new SymbolSolverCollectionStrategy()).collect(root);
private final Path root = CodeGenerationUtils.mavenModuleRoot(JavaParser.class);
private final ProjectRoot projectRoot = new SymbolSolverCollectionStrategy().collect(root);

@Test
public void resolveExpressions() throws IOException {
Log.setAdapter(new Log.StandardOutStandardErrorAdapter());
Optional<SourceRoot> sourceRoot = projectRoot.getSourceRoot(root.resolve("javaparser-core/src/main/java"));
assertTrue(sourceRoot.isPresent());
int unresolved = 0;
for (ParseResult<CompilationUnit> parseResult : sourceRoot.get().tryToParse()) {
CompilationUnit compilationUnit = parseResult.getResult().get();
for (MethodDeclaration expr : compilationUnit.findAll(MethodDeclaration.class)) {
try {
expr.resolve().getQualifiedSignature();
} catch (UnsupportedOperationException e) {
// not supported operation, just skip
} catch (Exception e) {
unresolved++;
Log.error(e, "Unable to resolve %s from %s", expr, compilationUnit.getStorage().get().getPath());
SourceRoot sourceRoot = projectRoot.getSourceRoot(root.resolve("src/main/java")).get();
AtomicInteger unresolved = new AtomicInteger();
for (ParseResult<CompilationUnit> parseResult : sourceRoot.tryToParse()) {
parseResult.ifSuccessful(compilationUnit -> {
for (MethodDeclaration expr : compilationUnit.findAll(MethodDeclaration.class)) {
try {
expr.resolve().getQualifiedSignature();
} catch (UnsupportedOperationException e) {
// not supported operation, just skip
} catch (Exception e) {
unresolved.getAndIncrement();
Log.error(e, "Unable to resolve %s from %s", expr, compilationUnit.getStorage().get().getPath());
}
}
}
});
}
// not too many MethodDeclarations should be unresolved
assertTrue(unresolved < 10);
assertTrue(unresolved.get() < 10);
}
}

0 comments on commit daaeb29

Please sign in to comment.