// Path: lang/java/src/main/java/com/google/devtools/build/bfg/ReferencedClassesParser.java
// @AutoValue
// public abstract static class ImportDeclaration {
//   public abstract QualifiedName name();
// 
//   public abstract boolean isStatic();
// 
//   public static ImportDeclaration create(QualifiedName qname, boolean isStatic) {
//     return new AutoValue_ReferencedClassesParser_ImportDeclaration(qname, isStatic);
//   }
// }
// 
// Path: lang/java/src/main/java/com/google/devtools/build/bfg/ReferencedClassesParser.java
// @AutoValue
// public abstract static class Metadata {
//   static final Metadata EMPTY = create(0, 0, false);
// 
//   /** Line where a simple/qualified name starts. */
//   public abstract int line();
// 
//   /** Column where a simple/qualified name starts. */
//   public abstract int column();
// 
//   public abstract boolean isMethod();
// 
//   public static Metadata create(int line, int column, boolean isMethod) {
//     return new AutoValue_ReferencedClassesParser_Metadata(line, column, isMethod);
//   }
// }
// 
// Path: lang/java/src/main/java/com/google/devtools/build/bfg/ReferencedClassesParser.java
// @AutoValue
// public abstract static class QualifiedName {
//   public static final Pattern CLASS_NAME_PATTERN = Pattern.compile("^[A-Z][a-zA-Z0-9_$]*$");
// 
//   public static QualifiedName create(String value, Metadata metadata) {
//     return new AutoValue_ReferencedClassesParser_QualifiedName(value, metadata);
//   }
// 
//   public abstract String value();
// 
//   public abstract Metadata metadata();
// 
//   @Memoized
//   public ImmutableList<String> parts() {
//     return ImmutableList.copyOf(DOT_SPLITTER.split(value()));
//   }
// 
//   private static int findTopLevelName(List<String> parts) {
//     for (int i = 0; i < parts.size(); i++) {
//       String part = parts.get(i);
//       if (CLASS_NAME_PATTERN.matcher(part).matches()) {
//         // if i == 0, 's' starts with a capitalized-camel name,
//         // e.g., "MobileLocalDetailsJslayoutProto".
//         return i > 0 ? i : -1;
//       }
//       if (isLowerCase(part)) {
//         continue;
//       }
//       return -1;
//     }
//     return -1;
//   }
// 
//   /**
//    * "java.util.Map" => "java.util.Map" "java.util.Map.Entry" => "java.util.Map"
//    * "org.mockito.Mockito.mock" => "org.mockito.Mockito"
//    */
//   public QualifiedName getTopLevelQualifiedName() {
//     return create(DOT_JOINER.join(parts().subList(0, findTopLevelName(parts()) + 1)), metadata());
//   }
// }


import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.truth.Truth.assertThat;
import static java.util.stream.Collectors.toMap;
import static org.junit.Assert.assertTrue;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.google.devtools.build.bfg.ReferencedClassesParser.ImportDeclaration;
import com.google.devtools.build.bfg.ReferencedClassesParser.Metadata;
import com.google.devtools.build.bfg.ReferencedClassesParser.QualifiedName;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
    assertThat(parse("").fullyQualifiedClassName).isNull();
    assertThat(parse("package foo;").fullyQualifiedClassName).isNull();
    assertThat(parse("class A {}").fullyQualifiedClassName).isEqualTo("A");
    assertThat(parse("package foo; class A {}").fullyQualifiedClassName).isEqualTo("foo.A");
  }

  /**
   * Tests that we report methods encountered in a Java file, but only if they aren't defined in
   * this compilation unit. As a special case, tests that we don't report that 'definedInSameClass'
   * needs to be imported. (the type of its parameter triggers a bug in Eclipse that we work around,
   * so needs testing.)
   */
  @Test
  public void reportMethodInvocations() {
    String source =
        joiner.join(
            "import static com.Foo.f;",
            "import com.Bar;",
            "class A {",
            "  void foo() {",
            "    definedInSameClass(null);",
            "    unknownMethod();",
            "  }",
            "  void definedInSameClass(Abstract.Builder<?> foo) { }",
            "  static class Inner {",
            "    void unknownMethod() {",
            "      foo();",
            "      foo2();",
            "    }",
            "  }",
// Path: lang/java/src/main/java/com/google/devtools/build/bfg/ReferencedClassesParser.java
// @AutoValue
// public abstract static class ImportDeclaration {
//   public abstract QualifiedName name();
// 
//   public abstract boolean isStatic();
// 
//   public static ImportDeclaration create(QualifiedName qname, boolean isStatic) {
//     return new AutoValue_ReferencedClassesParser_ImportDeclaration(qname, isStatic);
//   }
// }
// 
// Path: lang/java/src/main/java/com/google/devtools/build/bfg/ReferencedClassesParser.java
// @AutoValue
// public abstract static class Metadata {
//   static final Metadata EMPTY = create(0, 0, false);
// 
//   /** Line where a simple/qualified name starts. */
//   public abstract int line();
// 
//   /** Column where a simple/qualified name starts. */
//   public abstract int column();
// 
//   public abstract boolean isMethod();
// 
//   public static Metadata create(int line, int column, boolean isMethod) {
//     return new AutoValue_ReferencedClassesParser_Metadata(line, column, isMethod);
//   }
// }
// 
// Path: lang/java/src/main/java/com/google/devtools/build/bfg/ReferencedClassesParser.java
// @AutoValue
// public abstract static class QualifiedName {
//   public static final Pattern CLASS_NAME_PATTERN = Pattern.compile("^[A-Z][a-zA-Z0-9_$]*$");
// 
//   public static QualifiedName create(String value, Metadata metadata) {
//     return new AutoValue_ReferencedClassesParser_QualifiedName(value, metadata);
//   }
// 
//   public abstract String value();
// 
//   public abstract Metadata metadata();
// 
//   @Memoized
//   public ImmutableList<String> parts() {
//     return ImmutableList.copyOf(DOT_SPLITTER.split(value()));
//   }
// 
//   private static int findTopLevelName(List<String> parts) {
//     for (int i = 0; i < parts.size(); i++) {
//       String part = parts.get(i);
//       if (CLASS_NAME_PATTERN.matcher(part).matches()) {
//         // if i == 0, 's' starts with a capitalized-camel name,
//         // e.g., "MobileLocalDetailsJslayoutProto".
//         return i > 0 ? i : -1;
//       }
//       if (isLowerCase(part)) {
//         continue;
//       }
//       return -1;
//     }
//     return -1;
//   }
// 
//   /**
//    * "java.util.Map" => "java.util.Map" "java.util.Map.Entry" => "java.util.Map"
//    * "org.mockito.Mockito.mock" => "org.mockito.Mockito"
//    */
//   public QualifiedName getTopLevelQualifiedName() {
//     return create(DOT_JOINER.join(parts().subList(0, findTopLevelName(parts()) + 1)), metadata());
//   }
// }


// Path: lang/java/src/test/java/com/google/devtools/build/bfg/ReferencedClassesParserTest.java
import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.truth.Truth.assertThat;
import static java.util.stream.Collectors.toMap;
import static org.junit.Assert.assertTrue;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.google.devtools.build.bfg.ReferencedClassesParser.ImportDeclaration;
import com.google.devtools.build.bfg.ReferencedClassesParser.Metadata;
import com.google.devtools.build.bfg.ReferencedClassesParser.QualifiedName;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

    assertThat(parse("").fullyQualifiedClassName).isNull();
    assertThat(parse("package foo;").fullyQualifiedClassName).isNull();
    assertThat(parse("class A {}").fullyQualifiedClassName).isEqualTo("A");
    assertThat(parse("package foo; class A {}").fullyQualifiedClassName).isEqualTo("foo.A");
  }

  /**
   * Tests that we report methods encountered in a Java file, but only if they aren't defined in
   * this compilation unit. As a special case, tests that we don't report that 'definedInSameClass'
   * needs to be imported. (the type of its parameter triggers a bug in Eclipse that we work around,
   * so needs testing.)
   */
  @Test
  public void reportMethodInvocations() {
    String source =
        joiner.join(
            "import static com.Foo.f;",
            "import com.Bar;",
            "class A {",
            "  void foo() {",
            "    definedInSameClass(null);",
            "    unknownMethod();",
            "  }",
            "  void definedInSameClass(Abstract.Builder<?> foo) { }",
            "  static class Inner {",
            "    void unknownMethod() {",
            "      foo();",
            "      foo2();",
            "    }",
            "  }",
            "}");