@Override public int getSeverity() { if (ApiPlugin.isRunningInFramework()) { return ApiPlugin.getDefault() .getSeverityLevel(ApiProblemFactory.getProblemSeverityId(this), null); } return ApiPlugin.SEVERITY_WARNING; }
/* (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.provisional.search.IApiProblemDetector#createProblems() */ public List createProblems() { List references = getRetainedReferences(); List problems = new LinkedList(); Iterator iterator = references.iterator(); while (iterator.hasNext()) { IReference reference = (IReference) iterator.next(); if (reference.getResolvedReference() == null) { // TODO: unresolved reference } else { if (isProblem(reference)) { try { IApiProblem problem = null; IApiComponent component = reference.getMember().getApiComponent(); if (component instanceof ProjectComponent) { ProjectComponent ppac = (ProjectComponent) component; IJavaProject project = ppac.getJavaProject(); problem = createProblem(reference, project); } else { problem = createProblem(reference); } if (problem != null) { problems.add(problem); } } catch (CoreException e) { ApiPlugin.log(e.getStatus()); } } } } return problems; }
/* * (non-Javadoc) * @see * org.eclipse.pde.api.tools.internal.provisional.search.IApiProblemDetector * #createProblems() */ @Override public List<IApiProblem> createProblems() { List<IReference> references = getRetainedReferences(); List<IApiProblem> problems = new LinkedList<IApiProblem>(); for (IReference reference : references) { if (isProblem(reference)) { try { IApiProblem problem = null; IApiComponent component = reference.getMember().getApiComponent(); if (component instanceof ProjectComponent) { ProjectComponent ppac = (ProjectComponent) component; IJavaProject project = ppac.getJavaProject(); problem = createProblem(reference, project); } else { problem = createProblem(reference); } if (problem != null) { problems.add(problem); } } catch (CoreException e) { ApiPlugin.log(e.getStatus()); } } } return problems; }
/** * Scans the specified source {@linkplain CompilationUnit} for contributed API javadoc tags. Tags * on methods will have unresolved signatures. * * @param source the source file to scan for tags * @param description the API description to annotate with any new tag rules found * @param container optional class file container containing the class file for the given source * that can be used to resolve method signatures if required (for tags on methods). If not * provided (<code>null</code>), method signatures will be unresolved. * @param options a map of Java compiler options to use when creating the AST to scan or <code> * null</code> if default options should be used * @param monitor * @throws CoreException */ public void scan( CompilationUnit source, IApiDescription description, IApiTypeContainer container, Map options, IProgressMonitor monitor) throws CoreException { SubMonitor localmonitor = SubMonitor.convert(monitor, 2); ASTParser parser = ASTParser.newParser(AST.JLS3); InputStream inputStream = null; try { inputStream = source.getInputStream(); parser.setSource( Util.getInputStreamAsCharArray( inputStream, -1, System.getProperty("file.encoding"))); // $NON-NLS-1$ } catch (FileNotFoundException e) { throw new CoreException( new Status( IStatus.ERROR, ApiPlugin.PLUGIN_ID, MessageFormat.format( "Compilation unit source not found: {0}", new String[] {source.getName()}), e)); //$NON-NLS-1$ } catch (IOException e) { if (DEBUG) { System.err.println(source.getName()); } throw new CoreException( new Status( IStatus.ERROR, ApiPlugin.PLUGIN_ID, MessageFormat.format( "Error reading compilation unit: {0}", new String[] {source.getName()}), e)); //$NON-NLS-1$ } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { ApiPlugin.log(e); } } } Util.updateMonitor(localmonitor); Map loptions = options; if (loptions == null) { loptions = JavaCore.getOptions(); } loptions.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); parser.setCompilerOptions(loptions); org.eclipse.jdt.core.dom.CompilationUnit cunit = (org.eclipse.jdt.core.dom.CompilationUnit) parser.createAST(localmonitor.newChild(1)); Visitor visitor = new Visitor(description, container); cunit.accept(visitor); if (visitor.getException() != null) { throw visitor.getException(); } }
/* * (non-Javadoc) * @see * org.eclipse.pde.api.tools.internal.search.AbstractProblemDetector#isProblem * (org.eclipse.pde.api.tools.internal.provisional.model.IReference) */ @Override protected boolean isProblem(IReference reference) { // the reference must be in the system library try { IApiMember member = reference.getMember(); IApiComponent apiComponent = member.getApiComponent(); String[] lowestEEs = apiComponent.getLowestEEs(); if (lowestEEs == null) { // this should not be true for Eclipse bundle as they should // always have a EE set return false; } loop: for (int i = 0, max = lowestEEs.length; i < max; i++) { String lowestEE = lowestEEs[i]; int eeValue = ProfileModifiers.getValue(lowestEE); if (eeValue == ProfileModifiers.NO_PROFILE_VALUE) { return false; } if (!((Reference) reference).resolve(eeValue)) { /* * Make sure that the resolved reference doesn't below to * one of the imported package of the current component */ if (apiComponent instanceof BundleComponent) { BundleDescription bundle = ((BundleComponent) apiComponent).getBundleDescription(); ImportPackageSpecification[] importPackages = bundle.getImportPackages(); String referencedTypeName = reference.getReferencedTypeName(); int index = referencedTypeName.lastIndexOf('.'); String packageName = referencedTypeName.substring(0, index); for (int j = 0, max2 = importPackages.length; j < max2; j++) { ImportPackageSpecification importPackageSpecification = importPackages[j]; // get the IPackageDescriptor for the element // descriptor String importPackageName = importPackageSpecification.getName(); if (importPackageName.equals(packageName)) { continue loop; } } } if (this.referenceEEs == null) { this.referenceEEs = new HashMap<IReference, Integer>(3); } this.referenceEEs.put(reference, new Integer(eeValue)); return true; } } } catch (CoreException e) { ApiPlugin.log(e); } return false; }
protected boolean isReferenceFromComponent(IReference reference, Object componentId) { if (componentId != null) { final IApiComponent apiComponent = reference.getResolvedReference().getApiComponent(); // API component is either component id itself or one of its fragment if (apiComponent.getSymbolicName().equals(componentId)) { return true; } try { final IApiComponent host = apiComponent.getHost(); return host != null && host.getSymbolicName().equals(componentId); } catch (CoreException e) { ApiPlugin.log(e); } } return false; }
/** * Returns whether the resolved reference is a real problem. * * @param reference * @return whether a problem */ protected boolean isProblem(IReference reference) { // by default fragment -> host references are not problems // https://bugs.eclipse.org/bugs/show_bug.cgi?id=255659 IApiMember member = reference.getResolvedReference(); if (member != null) { IApiMember local = reference.getMember(); try { IApiComponent lcomp = local.getApiComponent(); if (lcomp != null && lcomp.isFragment()) { return !lcomp.getHost().equals(member.getApiComponent()); } } catch (CoreException ce) { ApiPlugin.log(ce); } } return true; }
/* * (non-Javadoc) * @see * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom * .Javadoc) */ @Override public boolean visit(Javadoc node) { Set<String> tagnames = ApiPlugin.getJavadocTagManager().getAllTagNames(); List<TagElement> tags = node.tags(); if (fExistingTags == null) { fExistingTags = new HashMap<String, Boolean>(tags.size()); } String name = null; for (TagElement tag : tags) { name = tag.getTagName(); if (name == null) { continue; } if (tagnames.contains(name)) { // only add existing API tools tags fExistingTags.put(name, Boolean.valueOf(tag.fragments().isEmpty())); } } return false; }
/* * (non-Javadoc) * @see * org.eclipse.pde.api.tools.internal.provisional.builder.IApiProblemDetector * # * considerReference(org.eclipse.pde.api.tools.internal.provisional.builder. * IReference) */ @Override public boolean considerReference(IReference reference) { try { IApiComponent apiComponent = reference.getMember().getApiComponent(); IApiBaseline baseline = apiComponent.getBaseline(); if (baseline == null) { return false; } String referencedTypeName = reference.getReferencedTypeName(); // extract the package name int index = referencedTypeName.lastIndexOf('.'); if (index == -1) { return false; } String substring = referencedTypeName.substring(0, index); IApiComponent[] resolvePackages = baseline.resolvePackage(apiComponent, substring); switch (resolvePackages.length) { case 1: { if (resolvePackages[0].isSystemComponent()) { switch (reference.getReferenceKind()) { case IReference.REF_OVERRIDE: case IReference.REF_CONSTANTPOOL: return false; default: break; } ((Reference) reference).setResolveStatus(false); retainReference(reference); return true; } break; } default: break; } } catch (CoreException e) { ApiPlugin.log(e); } return false; }
/** * 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); } }
/** * Computes all of the Javadoc completion proposals * * @param jcontext * @param corecontext * @return the complete list of Javadoc completion proposals or an empty list, never <code>null * </code> * @since 1.0.500 */ List<ICompletionProposal> computeJavadocProposals( JavaContentAssistInvocationContext jcontext, CompletionContext corecontext) { ICompilationUnit cunit = jcontext.getCompilationUnit(); if (cunit != null) { try { int offset = jcontext.getInvocationOffset(); IJavaElement element = cunit.getElementAt(offset); if (!isVisible(element)) { return Collections.EMPTY_LIST; } ImageDescriptor imagedesc = jcontext .getLabelProvider() .createImageDescriptor( org.eclipse.jdt.core.CompletionProposal.create( org.eclipse.jdt.core.CompletionProposal.JAVADOC_BLOCK_TAG, offset)); fImageHandle = (imagedesc == null ? null : imagedesc.createImage()); int type = getType(element); int member = IApiJavadocTag.MEMBER_NONE; switch (element.getElementType()) { case IJavaElement.METHOD: { IMethod method = (IMethod) element; member = IApiJavadocTag.MEMBER_METHOD; if (method.isConstructor()) { member = IApiJavadocTag.MEMBER_CONSTRUCTOR; } break; } case IJavaElement.FIELD: { member = IApiJavadocTag.MEMBER_FIELD; break; } default: break; } IApiJavadocTag[] tags = ApiPlugin.getJavadocTagManager().getTagsForType(type, member); int tagcount = tags.length; if (tagcount > 0) { ArrayList<ICompletionProposal> list = null; collectExistingTags(element, jcontext); String completiontext = null; int tokenstart = corecontext.getTokenStart(); int length = offset - tokenstart; for (int i = 0; i < tagcount; i++) { if (!acceptTag(tags[i], element)) { continue; } completiontext = tags[i].getCompleteTag(type, member); if (appliesToContext( jcontext.getDocument(), completiontext, tokenstart, (length > 0 ? length : 1))) { if (list == null) { list = new ArrayList<ICompletionProposal>(tagcount - i); } list.add( new APIToolsJavadocCompletionProposal( corecontext, completiontext, tags[i].getTagName(), fImageHandle)); } } if (list != null) { return list; } } } catch (JavaModelException e) { fErrorMessage = e.getMessage(); } } return Collections.EMPTY_LIST; }
/* * (non-Javadoc) * @see * org.eclipse.pde.api.tools.internal.search.AbstractTypeLeakDetector#isProblem * (org.eclipse.pde.api.tools.internal.provisional.model.IReference) */ @Override public boolean isProblem(IReference reference) { if (super.isProblem(reference)) { // check the use restrictions on the API type (can be extended or // not) IApiType type = (IApiType) reference.getMember(); IApiComponent component = type.getApiComponent(); try { if (type.isClass()) { int modifiers = 0; IApiAnnotations annotations = component.getApiDescription().resolveAnnotations(type.getHandle()); if (annotations != null) { // if annotations are null, the reference should not // have been retained // as it indicates a reference from a top level non // public type if (RestrictionModifiers.isExtendRestriction(annotations.getRestrictions())) { // The no extend restriction means only public // members can be seen modifiers = Flags.AccPublic; } else { if (Flags.isFinal(type.getModifiers())) { // if final then only public members can be seen modifiers = Flags.AccPublic; } else { // public and protected members can be seen modifiers = Flags.AccPublic | Flags.AccProtected; } } IApiType nonApiSuper = type.getSuperclass(); // collect all visible methods in non-API types Set<MethodKey> methods = new HashSet<MethodKey>(); while (!isAPIType(nonApiSuper)) { if (hasVisibleField(nonApiSuper, modifiers)) { // a visible field in a non-API type is a // definite leak return true; } gatherVisibleMethods(nonApiSuper, methods, modifiers); nonApiSuper = nonApiSuper.getSuperclass(); } if (methods.size() > 0) { // check if the visible members are part of an API // interface/class List<IApiType> apiTypes = new LinkedList<IApiType>(); apiTypes.add(type); gatherAPISuperTypes(apiTypes, type); for (IApiType t2 : apiTypes) { Set<MethodKey> apiMembers = new HashSet<MethodKey>(); gatherVisibleMethods(t2, apiMembers, modifiers); methods.removeAll(apiMembers); if (methods.size() == 0) { // there are no visible methods left that // are not part of an API type/interface return false; } } if (methods.size() > 0) { // there are visible members that are not part // of an API type/interface return true; } } } } else { // don't process interfaces, enums, annotations return true; } } catch (CoreException ce) { if (ApiPlugin.DEBUG_PROBLEM_DETECTOR) { ApiPlugin.log(ce); } return true; } } return false; }
/** Tests the {@link ApiBaselineManager} without the framework running */ @SuppressWarnings("unchecked") public class ApiBaselineManagerTests extends AbstractApiTest { static final String THREE = "three"; static final String TESTDEFAULT = "testdefault"; static final String ADDTEST = "addtest"; class SourceChangeVisitor extends ASTVisitor { String name = null; String signature = null; String tagname = null; ASTRewrite rewrite = null; boolean remove = false; public SourceChangeVisitor( String name, String signature, String tagname, boolean remove, ASTRewrite rewrite) { this.name = name; this.signature = signature; this.tagname = tagname; this.rewrite = rewrite; this.remove = remove; } /* (non-Javadoc) * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration) */ public boolean visit(FieldDeclaration node) { if (signature != null) { return false; } List<VariableDeclarationFragment> fields = node.fragments(); VariableDeclarationFragment fragment = null; for (Iterator<VariableDeclarationFragment> iter = fields.iterator(); iter.hasNext(); ) { fragment = iter.next(); if (fragment.getName().getFullyQualifiedName().equals(name)) { break; } } if (fragment != null) { updateTag(node); } return false; } /* (non-Javadoc) * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration) */ public boolean visit(MethodDeclaration node) { if (name.equals(node.getName().getFullyQualifiedName())) { if (signature.equals(Signatures.getMethodSignatureFromNode(node))) { updateTag(node); } } return false; } /* (non-Javadoc) * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclaration) */ public boolean visit(TypeDeclaration node) { if (name.equals(node.getName().getFullyQualifiedName())) { updateTag(node); return false; } return true; } /** * Updates a javadoc tag, by either adding a new one or removing an existing one * * @param body */ private void updateTag(BodyDeclaration body) { Javadoc docnode = body.getJavadoc(); AST ast = body.getAST(); if (docnode == null) { docnode = ast.newJavadoc(); rewrite.set(body, body.getJavadocProperty(), docnode, null); } ListRewrite lrewrite = rewrite.getListRewrite(docnode, Javadoc.TAGS_PROPERTY); if (remove) { List<TagElement> tags = (List<TagElement>) docnode.getStructuralProperty(Javadoc.TAGS_PROPERTY); if (tags != null) { TagElement tag = null; for (int i = 0; i < tags.size(); i++) { tag = tags.get(i); if (tagname.equals(tag.getTagName())) { lrewrite.remove(tag, null); } } } } else { TagElement newtag = ast.newTagElement(); newtag.setTagName(tagname); lrewrite.insertLast(newtag, null); } } } private IPath SRC_LOC = TestSuiteHelper.getPluginDirectoryPath() .append("test-source") .append("a") .append("b") .append("c"); private IPath PLUGIN_LOC = TestSuiteHelper.getPluginDirectoryPath().append("test-plugins"); private IApiBaselineManager fPMmanager = ApiPlugin.getDefault().getApiBaselineManager(); private final String TESTING_PACKAGE = "a.b.c"; /** @return the {@link IApiDescription} for the testing project */ private IApiDescription getTestProjectApiDescription() throws CoreException { IApiBaseline baseline = getWorkspaceBaseline(); assertNotNull("the workspace baseline must exist", baseline); IApiComponent component = baseline.getApiComponent(TESTING_PLUGIN_PROJECT_NAME); if (component != null) { return component.getApiDescription(); } return null; } /** * Creates and returns a test baseline with the given id. Also adds it to the baseline manager * * @param id * @return */ protected IApiBaseline getTestBaseline(String id) { IApiBaseline baseline = ApiModelFactory.newApiBaseline(id); fPMmanager.addApiBaseline(baseline); return baseline; } /** Tests trying to get the workspace baseline without the framework running */ public void testGetWorkspaceComponent() { IApiBaseline baseline = getWorkspaceBaseline(); assertTrue("the workspace baseline must not be null", baseline != null); } /** Tests that an API baseline can be added and retrieved successfully */ public void testAddBaseline() { IApiBaseline baseline = getTestBaseline(ADDTEST); assertTrue("the test baseline must have been created", baseline != null); assertTrue( "the testadd baseline must be in the manager", fPMmanager.removeApiBaseline(ADDTEST)); } /** Tests that an API baseline can be added/removed successfully */ public void testRemoveBaseline() { IApiBaseline baseline = getTestBaseline("removetest"); assertTrue("the testremove baseline must exist", baseline != null); baseline = fPMmanager.getApiBaseline("removetest"); assertTrue("the testremove baseline must be in the manager", baseline != null); assertTrue( "the testremove baseline should have been removed", fPMmanager.removeApiBaseline("removetest")); } /** Tests that the default baseline can be set/retrieved */ public void testSetDefaultBaseline() { try { IApiBaseline baseline = getTestBaseline(TESTDEFAULT); assertTrue("the testdefault baseline must exist", baseline != null); fPMmanager.setDefaultApiBaseline(TESTDEFAULT); baseline = fPMmanager.getDefaultApiBaseline(); assertTrue("the default baseline must be the testdefault baseline", baseline != null); } finally { fPMmanager.removeApiBaseline(TESTDEFAULT); } } /** Tests that all baselines added to the manager can be retrieved */ public void testGetAllBaselines() { try { fPMmanager.addApiBaseline(getTestBaseline(ADDTEST)); fPMmanager.addApiBaseline(getTestBaseline(TESTDEFAULT)); fPMmanager.addApiBaseline(getTestBaseline(THREE)); IApiBaseline[] baselines = fPMmanager.getApiBaselines(); assertTrue("there should be three baselines", baselines.length == 3); } finally { fPMmanager.removeApiBaseline(ADDTEST); fPMmanager.removeApiBaseline(TESTDEFAULT); fPMmanager.removeApiBaseline(THREE); } } /** Tests that all of the baselines have been removed */ public void testCleanUpMmanager() { try { fPMmanager.addApiBaseline(getTestBaseline(ADDTEST)); fPMmanager.addApiBaseline(getTestBaseline(TESTDEFAULT)); fPMmanager.addApiBaseline(getTestBaseline(THREE)); IApiBaseline[] baselines = fPMmanager.getApiBaselines(); assertTrue("there should be three baselines", baselines.length == 3); assertTrue( "the testadd baseline should have been removed", fPMmanager.removeApiBaseline(ADDTEST)); assertTrue( "the testdefault baseline should have been removed", fPMmanager.removeApiBaseline(TESTDEFAULT)); assertTrue( "the three baseline should have been removed", fPMmanager.removeApiBaseline(THREE)); assertTrue("There sould be no more baselines", fPMmanager.getApiBaselines().length == 0); } finally { fPMmanager.removeApiBaseline(ADDTEST); fPMmanager.removeApiBaseline(TESTDEFAULT); fPMmanager.removeApiBaseline(THREE); } } /** * Adds the given source to the given package in the given fragment root * * @param root the root to add the source to * @param packagename the name of the package e.g. a.b.c * @param sourcename the name of the source file without an extension e.g. TestClass1 */ public void assertTestSource(IPackageFragmentRoot root, String packagename, String sourcename) throws CoreException, InvocationTargetException, IOException { IPackageFragment fragment = root.getPackageFragment(packagename); FileUtils.importFileFromDirectory( SRC_LOC.append(sourcename + ".java").toFile(), fragment.getPath(), new NullProgressMonitor()); } /** * Adds the package with the given name to the given package fragment root * * @param the project to add the package to * @param srcroot the absolute path to the package fragment root to add the new package to * @param packagename the name of the new package * @return the new {@link IPackageFragment} or <code>null</code> */ public IPackageFragment assertTestPackage(IJavaProject project, IPath srcroot, String packagename) throws JavaModelException { IPackageFragment fragment = null; IPackageFragmentRoot root = project.findPackageFragmentRoot(srcroot); assertNotNull("the 'src' package fragment root must exist", root); fragment = root.createPackageFragment(packagename, true, new NullProgressMonitor()); assertNotNull("the new package '" + packagename + "' should have been created", fragment); return fragment; } /** * Adds a test library with the given name to the test projects' class path. The library is * imported from the {@link #PLUGIN_LOC} location. * * @param project the project to add the library classpath entry to * @param folderpath the path in the project where the library should be imported to * @param libname the name of the library */ public IFolder assertTestLibrary(IJavaProject project, IPath folderpath, String libname) throws CoreException, InvocationTargetException, IOException { IFolder folder = null; // import library folder = project.getProject().getFolder(folderpath); if (!folder.exists()) { folder.create(false, true, null); } FileUtils.importFileFromDirectory( PLUGIN_LOC.append(libname).toFile(), folder.getFullPath(), null); IPath libPath = folder.getFullPath().append(libname); // add to manifest bundle classpath ProjectUtils.addBundleClasspathEntry( project.getProject(), ProjectUtils.getBundleProjectService() .newBundleClasspathEntry(null, null, libPath.removeFirstSegments(1))); waitForAutoBuild(); return folder; } /** * Asserts if the given restriction is on the specified source * * @param packagename * @param sourcename */ public void assertSourceResctriction(String packagename, String sourcename, int restriction) throws CoreException { IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.typeDescriptor(packagename + "." + sourcename)); assertNotNull( "the annotations for " + packagename + "." + sourcename + " cannot be null", annot); assertTrue( "there must be a noinstantiate setting for TestClass1", annot.getRestrictions() == restriction); } /** Tests that closing an API aware project causes the workspace description to be updated */ public void testWPUpdateProjectClosed() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); assertNotNull("the workspace baseline must not be null", getWorkspaceBaseline()); IApiComponent component = getWorkspaceBaseline().getApiComponent(TESTING_PLUGIN_PROJECT_NAME); assertNotNull( "the change project api component must exist in the workspace baseline", component); project.getProject().close(new NullProgressMonitor()); component = getWorkspaceBaseline().getApiComponent(TESTING_PLUGIN_PROJECT_NAME); assertNull( "the test project api component should no longer exist in the workspace baseline", component); } /** Tests that opening an API aware project causes the workspace description to be updated */ public void testWPUpdateProjectOpen() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); if (project.getProject().isAccessible()) { project.getProject().close(new NullProgressMonitor()); } project.getProject().open(new NullProgressMonitor()); IApiBaseline baseline = getWorkspaceBaseline(); assertNotNull("the workspace baseline must not be null", baseline); IApiComponent component = baseline.getApiComponent(TESTING_PLUGIN_PROJECT_NAME); assertNotNull("the test project api component must exist in the workspace baseline", component); } /** * Tests that adding a source file to an API aware project causes the workspace description to be * updated This test adds <code>a.b.c.TestClass1</code> to the plug-in project */ public void testWPUpdateSourceAdded() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()) .append(ProjectUtils.SRC_FOLDER) .makeAbsolute() .makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); assertTestSource(root, TESTING_PACKAGE, "TestClass1"); assertSourceResctriction(TESTING_PACKAGE, "TestClass1", RestrictionModifiers.NO_INSTANTIATE); } /** * Tests that removing a source file from an API aware project causes the workspace description to * be updated */ public void testWPUpdateSourceRemoved() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); assertTestSource(root, TESTING_PACKAGE, "TestClass1"); IJavaElement element = project.findElement(new Path("a/b/c/TestClass1.java")); assertNotNull("the class a.b.c.TestClass1 must exist in the project", element); element.getResource().delete(true, new NullProgressMonitor()); IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.typeDescriptor("a.b.c.TestClass1")); assertNull("the annotations for a.b.c.TestClass1 should no longer be present", annot); } /** * Adds the specified tag to the source member defined by the member name and signature * * @param unit * @param membername * @param signature * @param tagname * @param remove * @throws CoreException * @throws MalformedTreeException * @throws BadLocationException */ private void updateTagInSource( ICompilationUnit unit, String membername, String signature, String tagname, boolean remove) throws CoreException, MalformedTreeException, BadLocationException { ASTParser parser = ASTParser.newParser(AST.JLS4); parser.setSource(unit); CompilationUnit cunit = (CompilationUnit) parser.createAST(new NullProgressMonitor()); assertNotNull("the ast compilation unit cannot be null", cunit); cunit.recordModifications(); ASTRewrite rewrite = ASTRewrite.create(cunit.getAST()); cunit.accept(new SourceChangeVisitor(membername, signature, tagname, remove, rewrite)); ITextFileBufferManager bm = FileBuffers.getTextFileBufferManager(); IPath path = cunit.getJavaElement().getPath(); try { bm.connect(path, LocationKind.IFILE, null); ITextFileBuffer tfb = bm.getTextFileBuffer(path, LocationKind.IFILE); IDocument document = tfb.getDocument(); TextEdit edits = rewrite.rewriteAST(document, null); edits.apply(document); tfb.commit(new NullProgressMonitor(), true); } finally { bm.disconnect(path, LocationKind.IFILE, null); } } /** * Tests that making Javadoc changes to the source file TestClass2 cause the workspace baseline to * be updated. * * <p>This test adds a @noinstantiate tag to the source file TestClass2 */ public void testWPUpdateSourceTypeChanged() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); NullProgressMonitor monitor = new NullProgressMonitor(); IPackageFragment fragment = root.getPackageFragment("a.b.c"); FileUtils.importFileFromDirectory( SRC_LOC.append("TestClass2.java").toFile(), fragment.getPath(), monitor); ICompilationUnit element = (ICompilationUnit) project.findElement(new Path("a/b/c/TestClass2.java")); assertNotNull("TestClass2 must exist in the test project", element); updateTagInSource(element, "TestClass2", null, "@noinstantiate", false); IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.typeDescriptor("a.b.c.TestClass2")); assertNotNull("the annotations for a.b.c.TestClass2 cannot be null", annot); assertTrue( "there must be a noinstantiate setting for TestClass2", (annot.getRestrictions() & RestrictionModifiers.NO_INSTANTIATE) != 0); assertTrue( "there must be a noextend setting for TestClass2", (annot.getRestrictions() & RestrictionModifiers.NO_EXTEND) != 0); } /** * Tests that tags updated on an inner type are updated in the workspace description. * * <p>This test adds a @noinstantiate tag to an inner class in TestClass3 */ public void testWPUpdateSourceInnerTypeChanged() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); assertTestSource(root, TESTING_PACKAGE, "TestClass3"); ICompilationUnit element = (ICompilationUnit) project.findElement(new Path("a/b/c/TestClass3.java")); assertNotNull("TestClass3 must exist in the test project", element); updateTagInSource(element, "InnerTestClass3", null, "@noinstantiate", false); IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.typeDescriptor("a.b.c.TestClass3$InnerTestClass3")); assertNotNull("the annotations for a.b.c.TestClass3$InnerTestClass3 cannot be null", annot); assertTrue( "there must be a noinstantiate setting for TestClass3$InnerTestClass3", (annot.getRestrictions() & RestrictionModifiers.NO_INSTANTIATE) != 0); assertTrue( "there must be a noextend setting for TestClass3$InnerTestClass3", (annot.getRestrictions() & RestrictionModifiers.NO_EXTEND) != 0); } /** * Tests that changing the javadoc for a method updates the workspace baseline * * <p>This test adds a @noextend tag to the method foo() in TestClass1 */ public void testWPUpdateSourceMethodChanged() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); assertTestSource(root, TESTING_PACKAGE, "TestClass1"); ICompilationUnit element = (ICompilationUnit) project.findElement(new Path("a/b/c/TestClass1.java")); assertNotNull("TestClass1 must exist in the test project", element); updateTagInSource(element, "foo", "()V", "@nooverride", false); IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.methodDescriptor("a.b.c.TestClass1", "foo", "()V")); assertNotNull("the annotations for foo() cannot be null", annot); assertTrue( "there must be a nooverride setting for foo()", (annot.getRestrictions() & RestrictionModifiers.NO_OVERRIDE) != 0); } /** * Tests that changing the javadoc for a field updates the workspace baseline * * <p>This test adds a @noextend tag to the field 'field' in TestField9 */ public void testWPUpdateSourceFieldChanged() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); assertTestSource(root, TESTING_PACKAGE, "TestField9"); ICompilationUnit element = (ICompilationUnit) project.findElement(new Path("a/b/c/TestField9.java")); assertNotNull("TestField9 must exist in the test project", element); updateTagInSource(element, "field", null, "@noreference", false); IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.fieldDescriptor("a.b.c.TestField9", "field")); assertNotNull("the annotations for 'field' cannot be null", annot); assertTrue( "there must be a noreference setting for 'field'", (annot.getRestrictions() & RestrictionModifiers.NO_REFERENCE) != 0); } /** * Tests that removing a tag from a method updates the workspace baseline * * <p>This test removes a @noextend tag to the method foo() in TestClass1 */ public void testWPUpdateSourceMethodRemoveTag() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); assertTestSource(root, TESTING_PACKAGE, "TestClass1"); ICompilationUnit element = (ICompilationUnit) project.findElement(new Path("a/b/c/TestClass1.java")); assertNotNull("TestClass1 must exist in the test project", element); updateTagInSource(element, "foo", "()V", "@nooverride", true); IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.methodDescriptor("a.b.c.TestClass1", "foo", "()V")); assertNotNull("the annotations for foo() cannot be null", annot); assertTrue("there must be no restrictions for foo()", annot.getRestrictions() == 0); } /** * Tests that removing a tag from a type updates the workspace baseline * * <p>This test removes a @noinstantiate tag to an inner class in TestClass3 */ public void testWPUpdateSourceTypeRemoveTag() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); assertTestSource(root, TESTING_PACKAGE, "TestClass3"); ICompilationUnit element = (ICompilationUnit) project.findElement(new Path("a/b/c/TestClass3.java")); assertNotNull("TestClass3 must exist in the test project", element); updateTagInSource(element, "InnerTestClass3", null, "@noextend", true); IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.typeDescriptor("a.b.c.TestClass3$InnerTestClass3")); assertNotNull("the annotations for 'InnerTestClass3' cannot be null", annot); assertTrue( "there must be a no restrictions for 'InnerTestClass3'", (annot.getRestrictions() & RestrictionModifiers.NO_INSTANTIATE) == 0); } /** * Tests that removing a tag from a field updates the workspace baseline * * <p>This test adds a @noextend tag to the field 'field' in TestField9 */ public void testWPUpdateSourceFieldRemoveTag() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IPackageFragmentRoot root = project.findPackageFragmentRoot( new Path(project.getElementName()).append(ProjectUtils.SRC_FOLDER).makeAbsolute()); assertNotNull("the 'src' package fragment root must exist", root); assertTestSource(root, TESTING_PACKAGE, "TestField9"); ICompilationUnit element = (ICompilationUnit) project.findElement(new Path("a/b/c/TestField9.java")); assertNotNull("TestField9 must exist in the test project", element); updateTagInSource(element, "field1", null, "@noreference", true); IApiDescription desc = getTestProjectApiDescription(); assertNotNull("the testing project api description must exist", desc); IApiAnnotations annot = desc.resolveAnnotations(Factory.fieldDescriptor("a.b.c.TestField9", "field")); assertNotNull("the annotations for 'field' cannot be null", annot); assertTrue("there must be a no restrictions for 'field'", annot.getRestrictions() == 0); } /** * Tests that a library added to the build and bundle class path of a project causes the class * file containers for the project to need to be recomputed * * @throws IOException * @throws InvocationTargetException * @throws CoreException */ public void testWPUpdateLibraryAddedToClasspath() throws Exception { IFolder folder = null; try { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IApiComponent component = getWorkspaceBaseline().getApiComponent(project.getElementName()); assertNotNull("the workspace component must exist", component); int before = component.getApiTypeContainers().length; // add to classpath folder = assertTestLibrary(project, new Path("libx"), "component.a_1.0.0.jar"); assertNotNull("The new library path should not be null", folder); // re-retrieve updated component component = getWorkspaceBaseline().getApiComponent(project.getElementName()); assertTrue( "there must be more containers after the addition", before < component.getApiTypeContainers().length); } finally { if (folder != null) { FileUtils.delete(folder); } } } /** Tests removing a library from the classpath of a project */ public void testWPUpdateLibraryRemovedFromClasspath() throws Exception { IPath libPath = null; try { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); // add to classpath IFolder folder = assertTestLibrary(project, new Path("libx"), "component.a_1.0.0.jar"); IApiComponent component = getWorkspaceBaseline().getApiComponent(project.getElementName()); assertNotNull("the workspace component must exist", component); int before = component.getApiTypeContainers().length; libPath = folder.getFullPath().append("component.a_1.0.0.jar"); // remove classpath entry ProjectUtils.removeFromClasspath(project, JavaCore.newLibraryEntry(libPath, null, null)); waitForAutoBuild(); // remove from bundle class path IBundleProjectService service = ProjectUtils.getBundleProjectService(); IBundleProjectDescription description = service.getDescription(project.getProject()); description.setBundleClasspath( new IBundleClasspathEntry[] { service.newBundleClasspathEntry(new Path(ProjectUtils.SRC_FOLDER), null, null) }); description.apply(null); waitForAutoBuild(); // retrieve updated component component = getWorkspaceBaseline().getApiComponent(project.getElementName()); assertTrue( "there must be less containers after the removal", before > component.getApiTypeContainers().length); } finally { if (libPath != null) { FileUtils.delete(libPath.toOSString()); } } } /** * Tests that changing the output folder settings for a project cause the class file containers to * be updated */ public void testWPUpdateDefaultOutputFolderChanged() throws Exception { IJavaProject project = getTestingProject(); assertNotNull("The testing project must exist", project); IContainer container = ProjectUtils.addFolderToProject(project.getProject(), "bin2"); assertNotNull("the new output folder cannot be null", container); IApiComponent component = getWorkspaceBaseline().getApiComponent(project.getElementName()); assertNotNull("the workspace component must exist", component); int before = component.getApiTypeContainers().length; project.setOutputLocation(container.getFullPath(), new NullProgressMonitor()); waitForAutoBuild(); assertTrue( "there must be the same number of containers after the change", before == component.getApiTypeContainers().length); assertTrue( "the new output location should be 'bin2'", "bin2".equalsIgnoreCase(project.getOutputLocation().toFile().getName())); } /** * Tests that the output folder settings for a source folder cause the class file containers to be * updated */ public void testWPUpdateOutputFolderSrcFolderChanged() throws Exception { IJavaProject project = getTestingProject(); IApiComponent component = getWorkspaceBaseline().getApiComponent(project.getElementName()); assertNotNull("the workspace component must exist", component); int before = component.getApiTypeContainers().length; ProjectUtils.addFolderToProject(project.getProject(), "bin3"); IContainer container = ProjectUtils.addFolderToProject(project.getProject(), "src2"); // add to bundle class path IBundleProjectService service = ProjectUtils.getBundleProjectService(); IBundleClasspathEntry next = service.newBundleClasspathEntry(new Path("src2"), new Path("bin3"), new Path("next.jar")); ProjectUtils.addBundleClasspathEntry(project.getProject(), next); waitForAutoBuild(); // retrieve updated component component = getWorkspaceBaseline().getApiComponent(project.getElementName()); assertTrue( "there must be one more container after the change", before < component.getApiTypeContainers().length); IPackageFragmentRoot root = project.getPackageFragmentRoot(container); assertTrue( "the class file container for src2 must be 'bin3'", "bin3".equals(root.getRawClasspathEntry().getOutputLocation().toFile().getName())); } /** 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); } /** * 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())); } /** * sets the given package name to be an Exported-Package * * @param name */ private void setPackageToApi(IJavaProject project, String name) throws CoreException { ProjectUtils.addExportedPackage(project.getProject(), name, false, null); } IJavaProject getTestingProject() { return JavaCore.create( ResourcesPlugin.getWorkspace().getRoot().getProject(TESTING_PLUGIN_PROJECT_NAME)); } /* (non-Javadoc) * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { createProject(TESTING_PLUGIN_PROJECT_NAME, new String[] {TESTING_PACKAGE}); setPackageToApi(getTestingProject(), TESTING_PACKAGE); } /* (non-Javadoc) * @see junit.framework.TestCase#tearDown() */ @Override protected void tearDown() throws Exception { deleteProject(TESTING_PLUGIN_PROJECT_NAME); getWorkspaceBaseline().dispose(); } }
/** * Creates a problem for a specific reference in the workspace * * @param reference reference * @param associated java project (with reference source location) * @return problem or <code>null</code> if none * @exception CoreException if something goes wrong */ protected IApiProblem createProblem(IReference reference, IJavaProject javaProject) { IProject project = javaProject.getProject(); if (ApiPlugin.getDefault().getSeverityLevel(getSeverityKey(), project) == ApiPlugin.SEVERITY_IGNORE) { return null; } try { String lookupName = getTypeName(reference.getMember()).replace('$', '.'); IType type = javaProject.findType(lookupName, new NullProgressMonitor()); if (type == null) { return null; } ICompilationUnit compilationUnit = type.getCompilationUnit(); if (compilationUnit == null) { return null; } IResource resource = Util.getResource(project, type); if (resource == null) { return null; } int charStart = -1; int charEnd = -1; int lineNumber = reference.getLineNumber(); IJavaElement element = compilationUnit; if (!Util.isManifest(resource.getProjectRelativePath()) && !type.isBinary()) { IDocument document = Util.getDocument(compilationUnit); // retrieve line number, char start and char end if (lineNumber > 0) { lineNumber--; } // get the source range for the problem try { Position pos = getSourceRange(type, document, reference); if (pos != null) { charStart = pos.getOffset(); if (charStart != -1) { charEnd = charStart + pos.getLength(); lineNumber = document.getLineOfOffset(charStart); } } } catch (CoreException e) { ApiPlugin.log(e); return null; } catch (BadLocationException e) { ApiPlugin.log(e); return null; } if (charStart > -1) { element = compilationUnit.getElementAt(charStart); } } return ApiProblemFactory.newApiUsageProblem( resource.getProjectRelativePath().toPortableString(), type.getFullyQualifiedName(), getMessageArgs(reference), new String[] { IApiMarkerConstants.MARKER_ATTR_HANDLE_ID, IApiMarkerConstants.API_MARKER_ATTR_ID }, new Object[] { (element == null ? compilationUnit.getHandleIdentifier() : element.getHandleIdentifier()), new Integer(IApiMarkerConstants.API_USAGE_MARKER_ID) }, lineNumber, charStart, charEnd, getElementType(reference), getProblemKind(), getProblemFlags(reference)); } catch (CoreException e) { ApiPlugin.log(e); } return null; }