/**
   * Tests that an exported package removal in the PDE model is reflected in the workspace api
   * baseline
   */
  public void testWPUpdateExportPackageRemoved() throws Exception {
    IJavaProject project = getTestingProject();
    assertNotNull("The testing project must exist", project);

    // add package
    assertTestPackage(
        project,
        new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute(),
        "export1");

    setPackageToApi(project, "export1");
    IApiAnnotations annot =
        getTestProjectApiDescription().resolveAnnotations(Factory.packageDescriptor("export1"));
    assertNotNull("there must be an annotation for the new exported package", annot);
    assertTrue(
        "the newly exported package must be API visibility",
        annot.getVisibility() == VisibilityModifiers.API);

    // remove exported packages
    IBundleProjectService service = ProjectUtils.getBundleProjectService();
    IBundleProjectDescription description = service.getDescription(project.getProject());
    description.setPackageExports(null);
    description.apply(null);

    // check the API description
    annot = getTestProjectApiDescription().resolveAnnotations(Factory.packageDescriptor("export1"));
    assertNotNull("should still be an annotation for the package", annot);
    assertTrue(
        "unexported package must be private", VisibilityModifiers.isPrivate(annot.getVisibility()));
  }
  /** Tests that adding a package does not update the workspace baseline */
  public void testWPUpdatePackageAdded() throws Exception {
    IJavaProject project = getTestingProject();
    assertNotNull("The testing project must exist", project);

    // add the package
    assertTestPackage(
        project,
        new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute(),
        "a.test1.c.d");

    IApiDescription desc = getTestProjectApiDescription();
    assertNotNull("the testing project api description must exist", desc);
    IApiAnnotations annot = desc.resolveAnnotations(Factory.packageDescriptor("a.test1.c.d"));
    assertNotNull("the annotations for package " + TESTING_PACKAGE + " should exist", annot);
  }
  /**
   * Tests that removing a package updates the workspace baseline This test removes the a.b.c
   * package being used in all tests thus far, and should be run last
   */
  public void testWPUpdatePackageRemoved() throws Exception {
    IJavaProject project = getTestingProject();
    assertNotNull("The testing project must exist", project);

    // add the package
    IPath srcroot =
        new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute();
    IPackageFragment fragment = assertTestPackage(project, srcroot, "a.test2");
    assertNotNull("the package " + TESTING_PACKAGE + " must exist", fragment);

    // remove the package
    fragment.delete(true, new NullProgressMonitor());

    IApiDescription desc = getTestProjectApiDescription();
    assertNotNull("the testing project api description must exist", desc);
    IApiAnnotations annot = desc.resolveAnnotations(Factory.packageDescriptor("a.test2"));
    assertNull("the annotations for package " + TESTING_PACKAGE + " should not exist", annot);
  }
  /**
   * Tests that an exported package addition in the PDE model is reflected in the workspace api
   * baseline
   */
  public void testWPUpdateExportPackageAdded() throws Exception {
    IJavaProject project = getTestingProject();
    assertNotNull("The testing project must exist", project);

    // add package
    assertTestPackage(
        project,
        new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute(),
        "export1");

    // update
    setPackageToApi(project, "export1");
    IApiAnnotations annot =
        getTestProjectApiDescription().resolveAnnotations(Factory.packageDescriptor("export1"));
    assertNotNull("there must be an annotation for the new exported package", annot);
    assertTrue(
        "the newly exported package must be API visibility",
        annot.getVisibility() == VisibilityModifiers.API);
  }
  /**
   * Tests that changing a directive to x-internal on an exported package causes the workspace api
   * baseline to be updated
   */
  public void testWPUPdateExportPackageDirectiveChangedToInternal() throws Exception {
    IJavaProject project = getTestingProject();
    assertNotNull("The testing project must exist", project);

    // add package
    assertTestPackage(
        project,
        new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute(),
        "export1");

    // export the package
    ProjectUtils.addExportedPackage(project.getProject(), "export1", true, null);

    // check the description
    IApiAnnotations annot =
        getTestProjectApiDescription().resolveAnnotations(Factory.packageDescriptor("export1"));
    assertNotNull("there must be an annotation for the new exported package", annot);
    assertTrue(
        "the changed exported package must be PRIVATE visibility",
        annot.getVisibility() == VisibilityModifiers.PRIVATE);
  }
Exemple #6
0
  /**
   * Visitor to scan a compilation unit. We only care about javadoc nodes that have either type or
   * enum declarations as parents, so we have to override the ones we don't care about.
   */
  static class Visitor extends ASTVisitor {

    private IApiDescription fDescription = null;

    /**
     * Package descriptor. Initialized to default package, and overridden if a package declaration
     * is visited.
     */
    private IPackageDescriptor fPackage = Factory.packageDescriptor(""); // $NON-NLS-1$

    /** Type descriptor for type currently being visited. */
    private IReferenceTypeDescriptor fType = null;

    /**
     * Used to look up binaries when resolving method signatures, or <code>null</code> if not
     * provided.
     */
    private IApiTypeContainer fContainer = null;

    /** List of exceptions encountered, or <code>null</code> */
    private CoreException fException;

    /**
     * Constructor
     *
     * @param description API description to annotate
     * @param container class file container or <code>null</code>, used to resolve method signatures
     */
    public Visitor(IApiDescription description, IApiTypeContainer container) {
      fDescription = description;
      fContainer = container;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Javadoc)
     */
    public boolean visit(Javadoc node) {
      List tags = node.tags();
      ASTNode parent = node.getParent();
      if (parent != null) {
        switch (parent.getNodeType()) {
          case ASTNode.TYPE_DECLARATION:
            {
              TypeDeclaration type = (TypeDeclaration) parent;
              if (type.isInterface()) {
                processTags(
                    fType,
                    pruneTags(tags, type),
                    IApiJavadocTag.TYPE_INTERFACE,
                    IApiJavadocTag.MEMBER_NONE);
              } else {
                processTags(
                    fType,
                    pruneTags(tags, type),
                    IApiJavadocTag.TYPE_CLASS,
                    IApiJavadocTag.MEMBER_NONE);
              }
              break;
            }
          case ASTNode.METHOD_DECLARATION:
            {
              MethodDeclaration method = (MethodDeclaration) parent;
              String signature = Signatures.getMethodSignatureFromNode(method);
              if (signature != null) {
                String methodname = method.getName().getFullyQualifiedName();
                int member = IApiJavadocTag.MEMBER_METHOD;
                if (method.isConstructor()) {
                  member = IApiJavadocTag.MEMBER_CONSTRUCTOR;
                  methodname = "<init>"; // $NON-NLS-1$
                }
                IMethodDescriptor descriptor = fType.getMethod(methodname, signature);
                processTags(descriptor, pruneTags(tags, method), getEnclosingType(method), member);
              }
              break;
            }
          case ASTNode.FIELD_DECLARATION:
            {
              FieldDeclaration field = (FieldDeclaration) parent;
              List fields = field.fragments();
              VariableDeclarationFragment fragment = null;
              for (Iterator iter = fields.iterator(); iter.hasNext(); ) {
                fragment = (VariableDeclarationFragment) iter.next();
                processTags(
                    fType.getField(fragment.getName().getFullyQualifiedName()),
                    pruneTags(tags, field),
                    getEnclosingType(field),
                    IApiJavadocTag.MEMBER_FIELD);
              }
              break;
            }
        }
      }
      return false;
    }

    private int getEnclosingType(ASTNode node) {
      ASTNode lnode = node;
      while (!(lnode instanceof AbstractTypeDeclaration)) {
        lnode = lnode.getParent();
      }
      if (lnode instanceof TypeDeclaration) {
        if (((TypeDeclaration) lnode).isInterface()) {
          return IApiJavadocTag.TYPE_INTERFACE;
        }
      }
      return IApiJavadocTag.TYPE_CLASS;
    }

    /**
     * A type has been entered - update the type being visited.
     *
     * @param name name from type node
     */
    private void enterType(SimpleName name) {
      if (fType == null) {
        fType = fPackage.getType(name.getFullyQualifiedName());
      } else {
        fType = fType.getType(name.getFullyQualifiedName());
      }
    }

    /** A type has been exited - update the type being visited. */
    private void exitType() {
      fType = fType.getEnclosingType();
    }

    /**
     * Processes the tags for the given {@link IElementDescriptor}
     *
     * @param descriptor the descriptor
     * @param tags the listing of tags from the AST
     * @param type one of <code>CLASS</code> or <code>INTERFACE</code>
     * @param member one of <code>METHOD</code> or <code>FIELD</code> or <code>NONE</code>
     */
    protected void processTags(IElementDescriptor descriptor, List tags, int type, int member) {
      JavadocTagManager jtm = ApiPlugin.getJavadocTagManager();
      TagElement tag = null;
      String tagname = null;
      int restrictions = RestrictionModifiers.NO_RESTRICTIONS;
      for (Iterator iter = tags.iterator(); iter.hasNext(); ) {
        tag = (TagElement) iter.next();
        tagname = tag.getTagName();
        restrictions |= jtm.getRestrictionsForTag(tagname, type, member);
      }
      if (restrictions != RestrictionModifiers.NO_RESTRICTIONS) {
        IElementDescriptor ldesc = descriptor;
        if (ldesc.getElementType() == IElementDescriptor.METHOD) {
          try {
            ldesc = resolveMethod((IMethodDescriptor) ldesc);
          } catch (CoreException e) {
            fException = e;
          }
        }
        fDescription.setRestrictions(ldesc, restrictions);
      }
    }

    /**
     * Method to post process returned flags from the {@link Javadoc} node of the element
     *
     * @param tags the tags to process
     * @param element the {@link ASTNode} the tag appears on
     * @return the list of valid tags to process restrictions for
     */
    private List pruneTags(final List tags, ASTNode node) {
      ArrayList pruned = new ArrayList(tags.size());
      TagElement tag = null;
      switch (node.getNodeType()) {
        case ASTNode.TYPE_DECLARATION:
          {
            TypeDeclaration type = (TypeDeclaration) node;
            int flags = type.getModifiers();
            for (Iterator iterator = tags.iterator(); iterator.hasNext(); ) {
              tag = (TagElement) iterator.next();
              String tagname = tag.getTagName();
              if (type.isInterface()
                  && ("@noextend".equals(tagname)
                      || //$NON-NLS-1$
                      "@noimplement".equals(tagname))) { // $NON-NLS-1$
                pruned.add(tag);
              } else {
                if ("@noextend".equals(tagname)) { // $NON-NLS-1$
                  if (!Flags.isFinal(flags)) {
                    pruned.add(tag);
                    continue;
                  }
                }
                if ("@noinstantiate".equals(tagname)) { // $NON-NLS-1$
                  if (!Flags.isAbstract(flags)) {
                    pruned.add(tag);
                    continue;
                  }
                }
              }
            }
            break;
          }
        case ASTNode.METHOD_DECLARATION:
          {
            MethodDeclaration method = (MethodDeclaration) node;
            int flags = method.getModifiers();
            for (Iterator iterator = tags.iterator(); iterator.hasNext(); ) {
              tag = (TagElement) iterator.next();
              if ("@noreference".equals(tag.getTagName())) { // $NON-NLS-1$
                pruned.add(tag);
                continue;
              }
              if ("@nooverride".equals(tag.getTagName())) { // $NON-NLS-1$
                ASTNode parent = method.getParent();
                int pflags = 0;
                if (parent instanceof BodyDeclaration) {
                  pflags = ((BodyDeclaration) parent).getModifiers();
                }
                if (!Flags.isFinal(flags) && !Flags.isStatic(flags) && !Flags.isFinal(pflags)) {
                  pruned.add(tag);
                  continue;
                }
              }
            }
            break;
          }
        case ASTNode.FIELD_DECLARATION:
          {
            FieldDeclaration field = (FieldDeclaration) node;
            for (Iterator iterator = tags.iterator(); iterator.hasNext(); ) {
              tag = (TagElement) iterator.next();
              boolean isfinal = Flags.isFinal(field.getModifiers());
              if (isfinal || (isfinal && Flags.isStatic(field.getModifiers()))) {
                break;
              }
              if ("@noreference".equals(tag.getTagName())) { // $NON-NLS-1$
                pruned.add(tag);
                break;
              }
            }
            break;
          }
      }
      return pruned;
    }

    /**
     * Returns whether to continue processing children.
     *
     * @return whether to continue processing children.
     */
    private boolean isContinue() {
      return fException == null;
    }

    /**
     * Returns an exception that aborted processing, or <code>null</code> if none.
     *
     * @return an exception that aborted processing, or <code>null</code> if none
     */
    CoreException getException() {
      return fException;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclaration)
     */
    public boolean visit(TypeDeclaration node) {
      if (isPrivate(node.getModifiers())) {
        return false;
      }
      enterType(node.getName());
      return isContinue();
    }
    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.TypeDeclaration)
     */
    public void endVisit(TypeDeclaration node) {
      if (!isPrivate(node.getModifiers())) {
        exitType();
      }
    }
    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration)
     */
    public void endVisit(AnnotationTypeDeclaration node) {
      if (!isPrivate(node.getModifiers())) {
        exitType();
      }
    }
    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration)
     */
    public boolean visit(AnnotationTypeDeclaration node) {
      if (isPrivate(node.getModifiers())) {
        return false;
      }
      enterType(node.getName());
      return isContinue();
    }
    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumDeclaration)
     */
    public boolean visit(EnumDeclaration node) {
      if (isPrivate(node.getModifiers())) {
        return false;
      }
      enterType(node.getName());
      return isContinue();
    }
    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.EnumDeclaration)
     */
    public void endVisit(EnumDeclaration node) {
      if (!isPrivate(node.getModifiers())) {
        exitType();
      }
    }
    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PackageDeclaration)
     */
    public boolean visit(PackageDeclaration node) {
      Name name = node.getName();
      fPackage = Factory.packageDescriptor(name.getFullyQualifiedName());
      return false;
    }
    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration)
     */
    public boolean visit(MethodDeclaration node) {
      if (isPrivate(node.getModifiers())) {
        return false;
      }
      return isContinue();
    }
    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration)
     */
    public boolean visit(FieldDeclaration node) {
      if (isPrivate(node.getModifiers())) {
        return false;
      }
      return isContinue();
    }

    private boolean isPrivate(int flags) {
      return Flags.isPrivate(flags);
    }
    /**
     * Returns a method descriptor with a resolved signature for the given method descriptor with an
     * unresolved signature.
     *
     * @param descriptor method to resolve
     * @return resolved method descriptor or the same method descriptor if unable to resolve
     * @exception CoreException if unable to resolve the method and a class file container was
     *     provided for this purpose
     */
    private IMethodDescriptor resolveMethod(IMethodDescriptor descriptor) throws CoreException {
      if (fContainer != null) {
        IReferenceTypeDescriptor type = descriptor.getEnclosingType();
        IApiTypeRoot classFile = fContainer.findTypeRoot(type.getQualifiedName());
        if (classFile != null) {
          IApiType structure = classFile.getStructure();
          if (structure != null) {
            IApiMethod[] methods = structure.getMethods();
            for (int i = 0; i < methods.length; i++) {
              IApiMethod method = methods[i];
              if (descriptor.getName().equals(method.getName())) {
                String signature = method.getSignature();
                String descriptorSignature = descriptor.getSignature().replace('/', '.');
                if (Signatures.matchesSignatures(
                    descriptorSignature, signature.replace('/', '.'))) {
                  return descriptor.getEnclosingType().getMethod(method.getName(), signature);
                }
                String genericSignature = method.getGenericSignature();
                if (genericSignature != null) {
                  if (Signatures.matchesSignatures(
                      descriptorSignature, genericSignature.replace('/', '.'))) {
                    return descriptor.getEnclosingType().getMethod(method.getName(), signature);
                  }
                }
              }
            }
          }
        }
        throw new CoreException(
            new Status(
                IStatus.ERROR,
                ApiPlugin.PLUGIN_ID,
                MessageFormat.format(
                    "Unable to resolve method signature: {0}",
                    new String[] {descriptor.toString()}),
                null)); //$NON-NLS-1$
      }
      return descriptor;
    }
  }
Exemple #7
0
 /* (non-Javadoc)
  * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PackageDeclaration)
  */
 public boolean visit(PackageDeclaration node) {
   Name name = node.getName();
   fPackage = Factory.packageDescriptor(name.getFullyQualifiedName());
   return false;
 }