use of com.facebook.buck.jvm.java.JavaFileParser in project buck by facebook.
the class FineGrainedJavaDependencySuggester method extractProvidedSymbolInfoFromSourceFile.
/**
* Extracts the features from {@code src} and updates the collections accordingly.
*/
private void extractProvidedSymbolInfoFromSourceFile(SourcePath src, JavaFileParser javaFileParser, Multimap<String, String> providedSymbolToRequiredSymbols, Map<String, PathSourcePath> providedSymbolToSrc) {
if (!(src instanceof PathSourcePath)) {
return;
}
PathSourcePath path = (PathSourcePath) src;
ProjectFilesystem filesystem = path.getFilesystem();
Optional<String> contents = filesystem.readFileIfItExists(path.getRelativePath());
if (!contents.isPresent()) {
throw new RuntimeException(String.format("Could not read file '%s'", path.getRelativePath()));
}
JavaFileParser.JavaFileFeatures features = javaFileParser.extractFeaturesFromJavaCode(contents.get());
// If there are multiple provided symbols, that is because there are inner classes. Choosing
// the shortest name will effectively select the top-level type.
String providedSymbol = Iterables.getFirst(features.providedSymbols, /* defaultValue */
null);
if (providedSymbol == null) {
console.getStdErr().printf("%s cowardly refuses to provide any types.\n", path.getRelativePath());
return;
}
providedSymbolToSrc.put(providedSymbol, path);
providedSymbolToRequiredSymbols.putAll(providedSymbol, features.requiredSymbols);
providedSymbolToRequiredSymbols.putAll(providedSymbol, features.exportedSymbols);
}
use of com.facebook.buck.jvm.java.JavaFileParser in project buck by facebook.
the class FineGrainedJavaDependencySuggester method suggestRefactoring.
/**
* Suggests a refactoring by printing it to stdout (with warnings printed to stderr).
* @throws IllegalArgumentException
*/
void suggestRefactoring() {
final TargetNode<?, ?> suggestedNode = graph.get(suggestedTarget);
if (!(suggestedNode.getConstructorArg() instanceof JavaLibraryDescription.Arg)) {
console.printErrorText(String.format("'%s' does not correspond to a Java rule", suggestedTarget));
throw new IllegalArgumentException();
}
JavaLibraryDescription.Arg arg = (JavaLibraryDescription.Arg) suggestedNode.getConstructorArg();
JavaFileParser javaFileParser = javaDepsFinder.getJavaFileParser();
Multimap<String, String> providedSymbolToRequiredSymbols = HashMultimap.create();
Map<String, PathSourcePath> providedSymbolToSrc = new HashMap<>();
for (SourcePath src : arg.srcs) {
extractProvidedSymbolInfoFromSourceFile(src, javaFileParser, providedSymbolToRequiredSymbols, providedSymbolToSrc);
}
// Create a MutableDirectedGraph from the providedSymbolToRequiredSymbols.
MutableDirectedGraph<String> symbolsDependencies = new MutableDirectedGraph<>();
// dependencies.
for (String providedSymbol : providedSymbolToSrc.keySet()) {
// Add a node for the providedSymbol in case it has no edges.
symbolsDependencies.addNode(providedSymbol);
for (String requiredSymbol : providedSymbolToRequiredSymbols.get(providedSymbol)) {
if (providedSymbolToRequiredSymbols.containsKey(requiredSymbol) && !providedSymbol.equals(requiredSymbol)) {
symbolsDependencies.addEdge(providedSymbol, requiredSymbol);
}
}
}
// Determine the strongly connected components.
Set<Set<String>> stronglyConnectedComponents = symbolsDependencies.findStronglyConnectedComponents();
// Maps a providedSymbol to the component that contains it.
Map<String, NamedStronglyConnectedComponent> namedComponentsIndex = new TreeMap<>();
Set<NamedStronglyConnectedComponent> namedComponents = new TreeSet<>();
for (Set<String> stronglyConnectedComponent : stronglyConnectedComponents) {
// We just use the first provided symbol in the strongly connected component as the canonical
// name for the component. Maybe not the best name, but certainly not the worst.
String name = Iterables.getFirst(stronglyConnectedComponent, /* defaultValue */
null);
if (name == null) {
throw new IllegalStateException("A strongly connected component was created with zero nodes.");
}
NamedStronglyConnectedComponent namedComponent = new NamedStronglyConnectedComponent(name, stronglyConnectedComponent);
namedComponents.add(namedComponent);
for (String providedSymbol : stronglyConnectedComponent) {
namedComponentsIndex.put(providedSymbol, namedComponent);
}
}
// Visibility argument.
StringBuilder visibilityBuilder = new StringBuilder(" visibility = [\n");
SortedSet<String> visibilities = FluentIterable.from(suggestedNode.getVisibilityPatterns()).transform(VisibilityPattern::getRepresentation).toSortedSet(Ordering.natural());
for (String visibility : visibilities) {
visibilityBuilder.append(" '" + visibility + "',\n");
}
visibilityBuilder.append(" ],\n");
String visibilityArg = visibilityBuilder.toString();
// Print out the new version of the original rule.
console.getStdOut().printf("java_library(\n" + " name = '%s',\n" + " exported_deps = [\n", suggestedTarget.getShortName());
for (NamedStronglyConnectedComponent namedComponent : namedComponents) {
console.getStdOut().printf(" ':%s',\n", namedComponent.name);
}
console.getStdOut().print(" ],\n" + visibilityArg + ")\n");
// Print out a rule for each of the strongly connected components.
JavaDepsFinder.DependencyInfo dependencyInfo = javaDepsFinder.findDependencyInfoForGraph(graph);
for (NamedStronglyConnectedComponent namedComponent : namedComponents) {
String buildRuleDefinition = createBuildRuleDefinition(namedComponent, providedSymbolToSrc, providedSymbolToRequiredSymbols, namedComponentsIndex, dependencyInfo, symbolsDependencies, visibilityArg);
console.getStdOut().print(buildRuleDefinition);
}
}
use of com.facebook.buck.jvm.java.JavaFileParser in project buck by facebook.
the class JavaDepsFinder method createJavaDepsFinder.
public static JavaDepsFinder createJavaDepsFinder(BuckConfig buckConfig, final CellPathResolver cellNames, ObjectMapper objectMapper, BuildEngineBuildContext buildContext, ExecutionContext executionContext, BuildEngine buildEngine) {
Optional<String> javaPackageMappingOption = buckConfig.getValue(BUCK_CONFIG_SECTION, "java-package-mappings");
ImmutableSortedMap<String, BuildTarget> javaPackageMapping;
if (javaPackageMappingOption.isPresent()) {
Stream<Map.Entry<String, BuildTarget>> entries = Splitter.on(',').omitEmptyStrings().withKeyValueSeparator("=>").split(javaPackageMappingOption.get()).entrySet().stream().map(entry -> {
String originalKey = entry.getKey().trim();
boolean appearsToBeJavaPackage = !originalKey.endsWith(".") && CharMatcher.javaUpperCase().matchesNoneOf(originalKey);
String key = appearsToBeJavaPackage ? originalKey + "." : originalKey;
BuildTarget buildTarget = BuildTargetParser.INSTANCE.parse(entry.getValue().trim(), BuildTargetPatternParser.fullyQualified(), cellNames);
return Maps.immutableEntry(key, buildTarget);
});
javaPackageMapping = ImmutableSortedMap.copyOf((Iterable<Map.Entry<String, BuildTarget>>) entries::iterator, Comparator.reverseOrder());
} else {
javaPackageMapping = ImmutableSortedMap.of();
}
JavaBuckConfig javaBuckConfig = buckConfig.getView(JavaBuckConfig.class);
JavacOptions javacOptions = javaBuckConfig.getDefaultJavacOptions();
JavaFileParser javaFileParser = JavaFileParser.createJavaFileParser(javacOptions);
return new JavaDepsFinder(javaPackageMapping, javaFileParser, objectMapper, buildContext, executionContext, buildEngine);
}
use of com.facebook.buck.jvm.java.JavaFileParser in project buck by facebook.
the class JavaLibrarySymbolsFinderTest method onlyNonGeneratedSrcsShouldAffectRuleKey.
@Test
@SuppressWarnings("PMD.PrematureDeclaration")
public void onlyNonGeneratedSrcsShouldAffectRuleKey() throws IOException {
TestDataHelper.createProjectWorkspaceForScenario(this, "java_library_symbols_finder", tmp).setUp();
final ProjectFilesystem projectFilesystem = new ProjectFilesystem(tmp.getRoot());
Function<String, SourcePath> convert = src -> new PathSourcePath(projectFilesystem, Paths.get(src));
SourcePath example1 = convert.apply("Example1.java");
SourcePath example2 = convert.apply("Example2.java");
final BuildTarget fakeBuildTarget = BuildTargetFactory.newInstance("//foo:GenEx.java");
SourcePath generated = new DefaultBuildTargetSourcePath(fakeBuildTarget);
final boolean shouldRecordRequiredSymbols = true;
JavaLibrarySymbolsFinder example1Finder = new JavaLibrarySymbolsFinder(ImmutableSortedSet.of(example1), javaFileParser, shouldRecordRequiredSymbols);
JavaLibrarySymbolsFinder example2Finder = new JavaLibrarySymbolsFinder(ImmutableSortedSet.of(example2), javaFileParser, shouldRecordRequiredSymbols);
JavaLibrarySymbolsFinder example1AndGeneratedSrcFinder = new JavaLibrarySymbolsFinder(ImmutableSortedSet.of(example1, generated), javaFileParser, shouldRecordRequiredSymbols);
// Mock out calls to a SourcePathResolver so we can create a legitimate
// DefaultRuleKeyFactory.
final SourcePathRuleFinder ruleFinder = createMock(SourcePathRuleFinder.class);
final SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder);
expect(ruleFinder.getRule(anyObject(SourcePath.class))).andAnswer(() -> {
SourcePath input = (SourcePath) EasyMock.getCurrentArguments()[0];
if (input instanceof ExplicitBuildTargetSourcePath) {
return Optional.of(new FakeBuildRule(fakeBuildTarget, pathResolver));
} else {
return Optional.empty();
}
}).anyTimes();
// Calculates the RuleKey for a JavaSymbolsRule with the specified JavaLibrarySymbolsFinder.
final FileHashCache fileHashCache = new StackedFileHashCache(ImmutableList.of(DefaultFileHashCache.createDefaultFileHashCache(projectFilesystem)));
final DefaultRuleKeyFactory ruleKeyFactory = new DefaultRuleKeyFactory(0, fileHashCache, pathResolver, ruleFinder);
Function<JavaLibrarySymbolsFinder, RuleKey> createRuleKey = finder -> {
JavaSymbolsRule javaSymbolsRule = new JavaSymbolsRule(BuildTargetFactory.newInstance("//foo:rule"), finder, ImmutableSortedSet.of(), ObjectMappers.newDefaultInstance(), projectFilesystem);
return ruleKeyFactory.build(javaSymbolsRule);
};
RuleKey key1 = createRuleKey.apply(example1Finder);
RuleKey key2 = createRuleKey.apply(example2Finder);
RuleKey key3 = createRuleKey.apply(example1AndGeneratedSrcFinder);
assertNotNull(key1);
assertNotNull(key2);
assertNotNull(key3);
assertNotEquals("Two instances of a JavaSymbolsRule with different srcs should change the RuleKey.", key1, key2);
assertEquals("Introducing an extra generated .java file to the srcs should not change the RuleKey.", key1, key3);
}
use of com.facebook.buck.jvm.java.JavaFileParser in project buck by facebook.
the class SymbolExtractor method extractSymbols.
public static Symbols extractSymbols(JavaFileParser javaFileParser, boolean shouldRecordRequiredSymbols, ImmutableSortedSet<Path> absolutePaths) {
Set<String> providedSymbols = new HashSet<>();
Set<String> requiredSymbols = new HashSet<>();
Set<String> exportedSymbols = new HashSet<>();
for (Path src : absolutePaths) {
String code;
try {
code = Files.toString(src.toFile(), Charsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
JavaFileParser.JavaFileFeatures features = javaFileParser.extractFeaturesFromJavaCode(code);
if (shouldRecordRequiredSymbols) {
requiredSymbols.addAll(features.requiredSymbols);
exportedSymbols.addAll(features.exportedSymbols);
}
providedSymbols.addAll(features.providedSymbols);
}
return new Symbols(providedSymbols, FluentIterable.from(requiredSymbols).filter(SymbolExtractor::isNotABuiltInSymbol), FluentIterable.from(exportedSymbols).filter(SymbolExtractor::isNotABuiltInSymbol));
}
Aggregations