/* * (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; }
/* (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.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; }
/* * (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.builder.AbstractProblemDetector# * getElementType * (org.eclipse.pde.api.tools.internal.provisional.builder.IReference) */ @Override protected int getElementType(IReference reference) { IApiMember member = reference.getMember(); switch (member.getType()) { case IApiElement.TYPE: return IElementDescriptor.TYPE; case IApiElement.METHOD: return IElementDescriptor.METHOD; case IApiElement.FIELD: return IElementDescriptor.FIELD; default: return 0; } }
/* * (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.builder.AbstractProblemDetector# * getMessageArgs * (org.eclipse.pde.api.tools.internal.provisional.builder.IReference) */ @Override protected String[] getMessageArgs(IReference reference) throws CoreException { IApiMember member = reference.getMember(); String eeValue = ProfileModifiers.getName(this.referenceEEs.get(reference).intValue()); String simpleTypeName = Signatures.getSimpleTypeName(reference.getReferencedTypeName()); if (simpleTypeName.indexOf('$') != -1) { simpleTypeName = simpleTypeName.replace('$', '.'); } switch (reference.getReferenceType()) { case IReference.T_TYPE_REFERENCE: { return new String[] { getDisplay(member, false), simpleTypeName, eeValue, }; } case IReference.T_FIELD_REFERENCE: { return new String[] { getDisplay(member, false), simpleTypeName, reference.getReferencedMemberName(), eeValue, }; } case IReference.T_METHOD_REFERENCE: { String referenceMemberName = reference.getReferencedMemberName(); if (Util.isConstructor(referenceMemberName)) { return new String[] { getDisplay(member, false), Signature.toString( reference.getReferencedSignature(), simpleTypeName, null, false, false), eeValue, }; } else { return new String[] { getDisplay(member, false), simpleTypeName, Signature.toString( reference.getReferencedSignature(), referenceMemberName, null, false, false), eeValue, }; } } default: break; } return null; }
/** * 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; }
/** * Returns whether the referenced type name matches a non-API package. * * @param reference * @return whether the referenced type name matches a non-API package */ protected boolean isNonAPIReference(IReference reference) { String packageName = Signatures.getPackageName(reference.getReferencedTypeName()); if (fNonApiPackageNames.contains(packageName)) { return true; } // could be a reference to a package visible type IApiMember member = reference.getMember(); IApiType type = null; if (member.getType() == IApiElement.TYPE) { type = (IApiType) member; } else { type = (IApiType) member.getAncestor(IApiElement.TYPE); } String origin = Signatures.getPackageName(type.getName()); if (packageName.equals(origin)) { return true; // possible package visible reference } return false; }
/** * @param reference * @return * @throws CoreException */ public IApiProblem createProblem(IReference reference) throws CoreException { int lineNumber = reference.getLineNumber(); if (lineNumber > 0) { lineNumber--; } String ltypename = getTypeName(reference.getMember()); return ApiProblemFactory.newApiUsageProblem( null, ltypename, getQualifiedMessageArgs(reference), new String[] {IApiMarkerConstants.API_MARKER_ATTR_ID}, new Object[] {new Integer(IApiMarkerConstants.API_USAGE_MARKER_ID)}, lineNumber, IApiProblem.NO_CHARRANGE, IApiProblem.NO_CHARRANGE, getElementType(reference), getProblemKind(), getProblemFlags(reference)); }
/* * (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; }
/* * (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.builder.AbstractProblemDetector# * getSourceRange(org.eclipse.jdt.core.IType, * org.eclipse.jface.text.IDocument, * org.eclipse.pde.api.tools.internal.provisional.builder.IReference) */ @Override protected Position getSourceRange(IType type, IDocument document, IReference reference) throws CoreException, BadLocationException { switch (reference.getReferenceType()) { case IReference.T_TYPE_REFERENCE: { int linenumber = reference.getLineNumber(); if (linenumber > 0) { // line number starts at 0 for the linenumber--; } if (linenumber > 0) { int offset = document.getLineOffset(linenumber); String line = document.get(offset, document.getLineLength(linenumber)); String qname = reference.getReferencedTypeName().replace('$', '.'); int first = line.indexOf(qname); if (first < 0) { qname = Signatures.getSimpleTypeName(reference.getReferencedTypeName()); qname = qname.replace('$', '.'); first = line.indexOf(qname); } Position pos = null; if (first > -1) { pos = new Position(offset + first, qname.length()); } else { // optimistically select the whole line since we can't // find the correct variable name and we can't just // select // the first occurrence pos = new Position(offset, line.length()); } return pos; } else { IApiMember apiMember = reference.getMember(); switch (apiMember.getType()) { case IApiElement.FIELD: { IApiField field = (IApiField) reference.getMember(); return getSourceRangeForField(type, reference, field); } case IApiElement.METHOD: { // reference in a method declaration IApiMethod method = (IApiMethod) reference.getMember(); return getSourceRangeForMethod(type, reference, method); } default: break; } // reference in a type declaration ISourceRange range = type.getNameRange(); Position pos = null; if (range != null) { pos = new Position(range.getOffset(), range.getLength()); } if (pos == null) { return defaultSourcePosition(type, reference); } return pos; } } case IReference.T_FIELD_REFERENCE: { int linenumber = reference.getLineNumber(); if (linenumber > 0) { return getFieldNameRange( reference.getReferencedTypeName(), reference.getReferencedMemberName(), document, reference); } // reference in a field declaration IApiField field = (IApiField) reference.getMember(); return getSourceRangeForField(type, reference, field); } case IReference.T_METHOD_REFERENCE: { if (reference.getLineNumber() >= 0) { String referenceMemberName = reference.getReferencedMemberName(); String methodName = null; boolean isConstructor = Util.isConstructor(referenceMemberName); if (isConstructor) { methodName = Signatures.getSimpleTypeName(reference.getReferencedTypeName().replace('$', '.')); } else { methodName = referenceMemberName; } Position pos = getMethodNameRange(isConstructor, methodName, document, reference); if (pos == null) { return defaultSourcePosition(type, reference); } return pos; } // reference in a method declaration IApiMethod method = (IApiMethod) reference.getMember(); return getSourceRangeForMethod(type, reference, method); } default: return null; } }
/* * (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; }
/** * 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; }