| /* |
| * Copyright 2014-present Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may |
| * not use this file except in compliance with the License. You may obtain |
| * a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package com.facebook.buck.java; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSortedSet; |
| import com.google.common.collect.Lists; |
| |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTParser; |
| import org.eclipse.jdt.core.dom.ASTVisitor; |
| import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.EnumDeclaration; |
| import org.eclipse.jdt.core.dom.PackageDeclaration; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| import org.eclipse.jdt.core.dom.TypeDeclarationStatement; |
| |
| import java.io.IOException; |
| import java.util.LinkedList; |
| import java.util.Map; |
| |
| /** |
| * Extracts the set of exported symbols (class and enum names) from a Java code file, using the |
| * ASTParser from Eclipse. |
| */ |
| public class JavaFileParser { |
| |
| private final int jlsLevel; |
| private final String javaVersion; |
| |
| private static final ImmutableMap<String, String> javaVersionMap = |
| ImmutableMap.<String, String>builder() |
| .put("1", JavaCore.VERSION_1_1) |
| .put("2", JavaCore.VERSION_1_2) |
| .put("3", JavaCore.VERSION_1_3) |
| .put("4", JavaCore.VERSION_1_4) |
| .put("5", JavaCore.VERSION_1_5) |
| .put("6", JavaCore.VERSION_1_6) |
| .put("7", JavaCore.VERSION_1_7) |
| .build(); |
| |
| private JavaFileParser(int jlsLevel, String javaVersion) { |
| this.jlsLevel = jlsLevel; |
| this.javaVersion = javaVersion; |
| } |
| |
| public static JavaFileParser createJavaFileParser(JavacOptions options) { |
| String javaVersion = Preconditions.checkNotNull(javaVersionMap.get(options.getSourceLevel())); |
| return new JavaFileParser(AST.JLS4, javaVersion); |
| } |
| |
| public ImmutableSortedSet<String> getExportedSymbolsFromString(String code) throws IOException { |
| ASTParser parser = ASTParser.newParser(jlsLevel); |
| parser.setSource(code.toCharArray()); |
| parser.setKind(ASTParser.K_COMPILATION_UNIT); |
| |
| @SuppressWarnings("unchecked") |
| Map<String, String> options = JavaCore.getOptions(); |
| JavaCore.setComplianceOptions(javaVersion, options); |
| parser.setCompilerOptions(options); |
| |
| final CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(/* monitor */ null); |
| |
| final ImmutableSortedSet.Builder<String> symbolsBuilder = ImmutableSortedSet.naturalOrder(); |
| |
| compilationUnit.accept(new ASTVisitor() { |
| @Override |
| public boolean visit(TypeDeclaration node) { |
| // Local classes can be declared inside of methods. Skip over these. |
| if (node.getParent() instanceof TypeDeclarationStatement) { |
| return true; |
| } |
| |
| symbolsBuilder.add(getFullyQualifiedTypeName(node)); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(EnumDeclaration node) { |
| symbolsBuilder.add(getFullyQualifiedTypeName(node)); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(AnnotationTypeDeclaration node) { |
| symbolsBuilder.add(getFullyQualifiedTypeName(node)); |
| return true; |
| } |
| }); |
| |
| return symbolsBuilder.build(); |
| } |
| |
| private String getFullyQualifiedTypeName(AbstractTypeDeclaration node) { |
| LinkedList<String> nameParts = Lists.newLinkedList(); |
| nameParts.add(node.getName().toString()); |
| ASTNode parent = node.getParent(); |
| while (!(parent instanceof CompilationUnit)) { |
| nameParts.addFirst(((AbstractTypeDeclaration) parent).getName().toString()); |
| parent = parent.getParent(); |
| } |
| |
| // A Java file might not have a package. Hopefully all of ours do though... |
| PackageDeclaration packageDecl = ((CompilationUnit) parent).getPackage(); |
| if (packageDecl != null) { |
| nameParts.addFirst(packageDecl.getName().toString()); |
| } |
| |
| return Joiner.on(".").join(nameParts); |
| } |
| } |