Search in sources :

Example 1 with JavaFileParser

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);
}
Also used : PathSourcePath(com.facebook.buck.rules.PathSourcePath) ProjectFilesystem(com.facebook.buck.io.ProjectFilesystem) JavaFileParser(com.facebook.buck.jvm.java.JavaFileParser)

Example 2 with JavaFileParser

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);
    }
}
Also used : JavaDepsFinder(com.facebook.buck.jvm.java.autodeps.JavaDepsFinder) SortedSet(java.util.SortedSet) TreeSet(java.util.TreeSet) Set(java.util.Set) HashMap(java.util.HashMap) JavaFileParser(com.facebook.buck.jvm.java.JavaFileParser) SourcePath(com.facebook.buck.rules.SourcePath) PathSourcePath(com.facebook.buck.rules.PathSourcePath) TreeSet(java.util.TreeSet) JavaLibraryDescription(com.facebook.buck.jvm.java.JavaLibraryDescription) PathSourcePath(com.facebook.buck.rules.PathSourcePath) TreeMap(java.util.TreeMap) MutableDirectedGraph(com.facebook.buck.graph.MutableDirectedGraph)

Example 3 with JavaFileParser

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);
}
Also used : JavacOptions(com.facebook.buck.jvm.java.JavacOptions) JavaBuckConfig(com.facebook.buck.jvm.java.JavaBuckConfig) JavaFileParser(com.facebook.buck.jvm.java.JavaFileParser) BuildTarget(com.facebook.buck.model.BuildTarget) Map(java.util.Map) ImmutableSortedMap(com.google.common.collect.ImmutableSortedMap)

Example 4 with JavaFileParser

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);
}
Also used : FakeBuildRule(com.facebook.buck.rules.FakeBuildRule) SourcePathRuleFinder(com.facebook.buck.rules.SourcePathRuleFinder) ObjectMappers(com.facebook.buck.util.ObjectMappers) SourcePath(com.facebook.buck.rules.SourcePath) TestDataHelper(com.facebook.buck.testutil.integration.TestDataHelper) TemporaryPaths(com.facebook.buck.testutil.integration.TemporaryPaths) ProjectFilesystem(com.facebook.buck.io.ProjectFilesystem) ImmutableList(com.google.common.collect.ImmutableList) JavaFileParser(com.facebook.buck.jvm.java.JavaFileParser) RuleKey(com.facebook.buck.rules.RuleKey) SourcePathResolver(com.facebook.buck.rules.SourcePathResolver) BuildTargetFactory(com.facebook.buck.model.BuildTargetFactory) DefaultRuleKeyFactory(com.facebook.buck.rules.keys.DefaultRuleKeyFactory) EasyMock.createMock(org.easymock.EasyMock.createMock) EasyMock.anyObject(org.easymock.EasyMock.anyObject) ImmutableSortedSet(com.google.common.collect.ImmutableSortedSet) Function(com.google.common.base.Function) ImmutableSet(com.google.common.collect.ImmutableSet) ExplicitBuildTargetSourcePath(com.facebook.buck.rules.ExplicitBuildTargetSourcePath) Assert.assertNotNull(org.junit.Assert.assertNotNull) Test(org.junit.Test) IOException(java.io.IOException) EasyMock.expect(org.easymock.EasyMock.expect) JavacOptions(com.facebook.buck.jvm.java.JavacOptions) EasyMock(org.easymock.EasyMock) DefaultFileHashCache(com.facebook.buck.util.cache.DefaultFileHashCache) BuildTarget(com.facebook.buck.model.BuildTarget) Assert.assertNotEquals(org.junit.Assert.assertNotEquals) DefaultBuildTargetSourcePath(com.facebook.buck.rules.DefaultBuildTargetSourcePath) StackedFileHashCache(com.facebook.buck.util.cache.StackedFileHashCache) Rule(org.junit.Rule) Stream(java.util.stream.Stream) Paths(java.nio.file.Paths) FileHashCache(com.facebook.buck.util.cache.FileHashCache) PathSourcePath(com.facebook.buck.rules.PathSourcePath) Optional(java.util.Optional) Assert.assertEquals(org.junit.Assert.assertEquals) DefaultFileHashCache(com.facebook.buck.util.cache.DefaultFileHashCache) StackedFileHashCache(com.facebook.buck.util.cache.StackedFileHashCache) FileHashCache(com.facebook.buck.util.cache.FileHashCache) DefaultRuleKeyFactory(com.facebook.buck.rules.keys.DefaultRuleKeyFactory) RuleKey(com.facebook.buck.rules.RuleKey) PathSourcePath(com.facebook.buck.rules.PathSourcePath) DefaultBuildTargetSourcePath(com.facebook.buck.rules.DefaultBuildTargetSourcePath) SourcePathRuleFinder(com.facebook.buck.rules.SourcePathRuleFinder) SourcePathResolver(com.facebook.buck.rules.SourcePathResolver) SourcePath(com.facebook.buck.rules.SourcePath) ExplicitBuildTargetSourcePath(com.facebook.buck.rules.ExplicitBuildTargetSourcePath) DefaultBuildTargetSourcePath(com.facebook.buck.rules.DefaultBuildTargetSourcePath) PathSourcePath(com.facebook.buck.rules.PathSourcePath) BuildTarget(com.facebook.buck.model.BuildTarget) FakeBuildRule(com.facebook.buck.rules.FakeBuildRule) StackedFileHashCache(com.facebook.buck.util.cache.StackedFileHashCache) ProjectFilesystem(com.facebook.buck.io.ProjectFilesystem) ExplicitBuildTargetSourcePath(com.facebook.buck.rules.ExplicitBuildTargetSourcePath) Test(org.junit.Test)

Example 5 with JavaFileParser

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));
}
Also used : Path(java.nio.file.Path) IOException(java.io.IOException) JavaFileParser(com.facebook.buck.jvm.java.JavaFileParser) HashSet(java.util.HashSet)

Aggregations

JavaFileParser (com.facebook.buck.jvm.java.JavaFileParser)6 PathSourcePath (com.facebook.buck.rules.PathSourcePath)4 ProjectFilesystem (com.facebook.buck.io.ProjectFilesystem)3 BuildTarget (com.facebook.buck.model.BuildTarget)3 SourcePath (com.facebook.buck.rules.SourcePath)3 JavacOptions (com.facebook.buck.jvm.java.JavacOptions)2 DefaultBuildTargetSourcePath (com.facebook.buck.rules.DefaultBuildTargetSourcePath)2 SourcePathResolver (com.facebook.buck.rules.SourcePathResolver)2 SourcePathRuleFinder (com.facebook.buck.rules.SourcePathRuleFinder)2 IOException (java.io.IOException)2 MutableDirectedGraph (com.facebook.buck.graph.MutableDirectedGraph)1 JavaBuckConfig (com.facebook.buck.jvm.java.JavaBuckConfig)1 JavaLibraryDescription (com.facebook.buck.jvm.java.JavaLibraryDescription)1 JavaDepsFinder (com.facebook.buck.jvm.java.autodeps.JavaDepsFinder)1 BuildTargetFactory (com.facebook.buck.model.BuildTargetFactory)1 BuildRuleResolver (com.facebook.buck.rules.BuildRuleResolver)1 DefaultTargetNodeToBuildRuleTransformer (com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer)1 ExplicitBuildTargetSourcePath (com.facebook.buck.rules.ExplicitBuildTargetSourcePath)1 FakeBuildRule (com.facebook.buck.rules.FakeBuildRule)1 RuleKey (com.facebook.buck.rules.RuleKey)1