blob: 406f88aa28747bc36e276ea66ffa8454ebbb7abf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.api.tools.internal.problems;
import org.eclipse.core.runtime.Path;
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
import org.eclipse.pde.api.tools.internal.provisional.descriptors.IElementDescriptor;
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
import org.eclipse.pde.api.tools.internal.util.Util;
/**
* A description of an api problem
*
* @since 1.0.0
*/
public class ApiProblem implements IApiProblem {
/**
* Human readable message for the problem
* TODO should not be passed in by user, should be derived (lazily loaded)
*/
private String fMessage = null;
/**
* The resource path for this problem
*/
private String fResourcePath = null;
/**
* The qualified type name for this problem
*/
private String fTypeName = null;
/**
* The composite id of the problem. Contains the category,
* element kind, kind, and flags for a specific problem
*/
private int fId = 0;
/**
* The listing of extra argument ids for the problem
*/
private String[] fExtraArgumentIds = null;
/**
* The listing of corresponding arguments for the problem
*/
private Object[] fExtraArguments = null;
/**
* The listing of arguments used to fill localized messages
*/
private String[] fMessageArguments = null;
/**
* The line number the problem occurred on
*/
private int fLineNumber = -1;
/**
* The start of a character selection range
*/
private int fCharStart = -1;
/**
* The end of a character selection range
*/
private int fCharEnd = -1;
/**
* Masks to get the original bits out of the id
*/
public static final int CATEGORY_MASK = 0xF0000000;
public static final int ELEMENT_KIND_MASK = 0x0F000000;
public static final int KIND_MASK = 0x00F00000;
public static final int FLAGS_MASK = 0x000FF000;
public static final int MESSAGE_MASK = 0x00000FFF;
/**
* Constant representing the name of the 'compatibilityStatus' attribute on API problem
* for the compatibility category.
* Value is: <code>compatibilityStatus</code>
*/
public static final String COMPATIBILITY_STATUS = "compatibilityStatus"; //$NON-NLS-1$
/**
* Constructor
* @param resource the resource this problem occurs on / in
* @param typeName the qualified type name this problem occurs on / in
* @param messageargs arguments to be passed into a localized message for the problem
* @param argumentids the ids of arguments passed into the problem
* @param arguments the arguments that correspond to the listing of ids
* @param linenumber the line this problem occurred on
* @param charstart the char selection start position
* @param charend the char selection end position
* @param severity the severity level of the problem
* @param id the id of the problem
*/
public ApiProblem(String path, String typeName, String[] messageargs, String[] argumentids, Object[] arguments, int linenumber, int charstart, int charend, int id) {
this.fResourcePath = path;
this.fTypeName = typeName;
this.fId = id;
this.fExtraArgumentIds = argumentids;
this.fExtraArguments = arguments;
this.fLineNumber = linenumber;
this.fCharStart = charstart;
this.fCharEnd = charend;
this.fMessageArguments = messageargs;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.IApiProblem#getId()
*/
public int getId() {
return fId;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.IApiProblem#getCategory()
*/
public int getCategory() {
return (fId & CATEGORY_MASK);
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem#getMessageid()
*/
public int getMessageid() {
return (fId & MESSAGE_MASK) >> OFFSET_MESSAGE;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.IApiProblem#getFlags()
*/
public int getFlags() {
return (fId & FLAGS_MASK) >> OFFSET_FLAGS;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.IApiProblem#getKind()
*/
public int getKind() {
return (fId & KIND_MASK) >> OFFSET_KINDS;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.IApiProblem#getMessage()
*/
public String getMessage() {
if(fMessage == null) {
fMessage = ApiProblemFactory.getLocalizedMessage(this);
}
return fMessage;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem#getResourcePath()
*/
public String getResourcePath() {
return fResourcePath;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.IApiProblem#getSeverity()
*/
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.IApiProblem#getElementKind()
*/
public int getElementKind() {
return (fId & ELEMENT_KIND_MASK) >> OFFSET_ELEMENT;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem#getLineNumber()
*/
public int getLineNumber() {
return fLineNumber;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem#getCharStart()
*/
public int getCharStart() {
return fCharStart;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem#getCharEnd()
*/
public int getCharEnd() {
return fCharEnd;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem#getExtraMarkerAttributeNames()
*/
public String[] getExtraMarkerAttributeIds() {
if(fExtraArguments == null || fExtraArgumentIds == null) {
return new String[0];
}
if(fExtraArgumentIds.length != fExtraArguments.length) {
return new String[0];
}
return fExtraArgumentIds;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem#getExtraMarkerAttributeValues()
*/
public Object[] getExtraMarkerAttributeValues() {
if(fExtraArguments == null || fExtraArgumentIds == null) {
return new String[0];
}
if(fExtraArgumentIds.length != fExtraArguments.length) {
return new String[0];
}
return fExtraArguments;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem#getMessageArguments()
*/
public String[] getMessageArguments() {
if(fMessageArguments == null) {
return new String[0];
}
return fMessageArguments;
}
public boolean equals(Object obj) {
if(obj instanceof IApiProblem) {
IApiProblem problem = (IApiProblem) obj;
if (problem.getId() == fId && argumentsEqual(problem.getMessageArguments())) {
String resourcePath = problem.getResourcePath();
if (resourcePath == null) {
if (this.fResourcePath != null) {
return false;
}
} else if (this.fResourcePath == null) {
return false;
} else if (!new Path(resourcePath).equals(new Path(fResourcePath))) {
return false;
}
String typeName = problem.getTypeName();
if (typeName == null) {
if (this.fTypeName != null) {
return false;
}
return true;
} else if (this.fTypeName == null) {
return false;
}
return typeName.equals(this.fTypeName);
}
return false;
}
return super.equals(obj);
}
/**
* Compares the complete list of message arguments
* @param arguments
* @return true if all of the arguments are equal, false otherwise
*/
private boolean argumentsEqual(String[] arguments) {
String[] currentArguments = getMessageArguments();
if((currentArguments == null && arguments != null) ||
(currentArguments != null && arguments == null)) {
return false;
}
boolean equal = true;
if(currentArguments.length != arguments.length) {
return false;
}
for(int i = 0; i < currentArguments.length; i++) {
equal &= currentArguments[i].equals(arguments[i]);
}
return equal;
}
/**
* Returns the deep hash code of the complete listing of message arguments
* @param arguments
* @return the hash code of the message arguments
*/
private int argumentsHashcode(String[] arguments) {
if(fMessageArguments == null) {
return 0;
}
int hashcode = 0;
for(int i = 0; i < fMessageArguments.length; i++) {
hashcode += fMessageArguments[i].hashCode();
}
return hashcode;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Api problem: "); //$NON-NLS-1$
buffer.append(fResourcePath != null ? fResourcePath : "no path").append("\n"); //$NON-NLS-1$//$NON-NLS-2$
buffer.append("\tseverity: "); //$NON-NLS-1$
buffer.append(Util.getSeverity(getSeverity())).append("\n"); //$NON-NLS-1$
buffer.append("\tcategory: "); //$NON-NLS-1$
buffer.append(ApiProblem.getProblemCategory(getCategory())).append("\n"); //$NON-NLS-1$
buffer.append("\telement kind: "); //$NON-NLS-1$
buffer.append(ApiProblem.getProblemElementKind(getCategory(), getElementKind())).append("\n"); //$NON-NLS-1$
buffer.append("\tkind: "); //$NON-NLS-1$
buffer.append(ApiProblem.getProblemKind(getCategory(), getKind())).append("\n"); //$NON-NLS-1$
buffer.append("\tflags: "); //$NON-NLS-1$
buffer.append(ApiProblem.getProblemFlagsName(getCategory(), getFlags())).append("\n"); //$NON-NLS-1$
buffer.append("\tmessage id: "); //$NON-NLS-1$
buffer.append(getMessageid());
buffer.append("\n\tmessage:"); //$NON-NLS-1$
buffer.append(getMessage());
return buffer.toString();
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return getId()
+ (fResourcePath != null ? fResourcePath.hashCode() : 0)
+ argumentsHashcode(fMessageArguments)
+ (fTypeName != null ? fTypeName.hashCode() : 0);
}
public String getTypeName() {
return this.fTypeName;
}
/**
* Returns the string representation of an element descriptor type or <code>null</code>
* if the kind is unknown
* @param kind
* @return the string of the kind or <code>null</code>
*/
public static String getDescriptorKind(int kind) {
switch(kind) {
case IElementDescriptor.PACKAGE: {
return "PACKAGE"; //$NON-NLS-1$
}
case IElementDescriptor.FIELD: {
return "FIELD"; //$NON-NLS-1$
}
case IElementDescriptor.METHOD: {
return "METHOD"; //$NON-NLS-1$
}
case IElementDescriptor.TYPE: {
return "REFERENCE_TYPE"; //$NON-NLS-1$
}
case IElementDescriptor.RESOURCE: {
return "RESOURCE"; //$NON-NLS-1$
}
}
return Util.UNKNOWN_ELEMENT_KIND;
}
/**
* Returns the string representation of the kind of since tab
* api problem
* @param kind
* @return the string for the since tag api problem kind
*/
public static String getTagsProblemKindName(int kind) {
switch(kind) {
case IApiProblem.SINCE_TAG_INVALID: return "INVALID_SINCE_TAGS"; //$NON-NLS-1$
case IApiProblem.SINCE_TAG_MALFORMED: return "MALFORMED_SINCE_TAGS"; //$NON-NLS-1$
case IApiProblem.SINCE_TAG_MISSING: return "MISSING_SINCE_TAGS"; //$NON-NLS-1$
}
return Util.UNKNOWN_KIND;
}
/**
* Returns the string representation of the kind of usage problem for
* an {@link IApiProblem} kind
* @param kind
* @return the string for the usage api problem kind
*/
public static String getUsageProblemKindName(int kind) {
switch(kind) {
case IApiProblem.ILLEGAL_EXTEND: return "ILLEGAL_EXTEND"; //$NON-NLS-1$
case IApiProblem.ILLEGAL_IMPLEMENT: return "ILLEGAL_IMPLEMENT"; //$NON-NLS-1$
case IApiProblem.ILLEGAL_INSTANTIATE: return "ILLEGAL_INSTANTIATE"; //$NON-NLS-1$
case IApiProblem.ILLEGAL_REFERENCE: return "ILLEGAL_REFERENCE"; //$NON-NLS-1$
case IApiProblem.ILLEGAL_OVERRIDE: return "ILLEGAL_OVERRIDE"; //$NON-NLS-1$
case IApiProblem.API_LEAK: return "API_LEAK"; //$NON-NLS-1$
case IApiProblem.UNSUPPORTED_TAG_USE: return "UNSUPPORTED_TAG_USE"; //$NON-NLS-1$
case IApiProblem.INVALID_REFERENCE_IN_SYSTEM_LIBRARIES: return "INVALID_REFERENCE_IN_SYSTEM_LIBRARIES"; //$NON-NLS-1$
case IApiProblem.UNUSED_PROBLEM_FILTERS: return "UNUSED_PROBLEM_FILTERS"; //$NON-NLS-1$
}
return Util.UNKNOWN_KIND;
}
/**
* Returns the string representation of the version problem kind.
* @param kind
* @return the string of the version API problem kind
*/
public static String getVersionProblemKindName(int kind) {
switch(kind) {
case IApiProblem.MINOR_VERSION_CHANGE: return "MINOR_VERSION_CHANGE"; //$NON-NLS-1$
case IApiProblem.MAJOR_VERSION_CHANGE: return "MAJOR_VERSION_CHANGE"; //$NON-NLS-1$
case IApiProblem.MAJOR_VERSION_CHANGE_NO_BREAKAGE: return "MAJOR_VERSION_CHANGE_NO_BREAKAGE"; //$NON-NLS-1$
case IApiProblem.MINOR_VERSION_CHANGE_NO_NEW_API: return "MINOR_VERSION_CHANGE_NO_NEW_API"; //$NON-NLS-1$
case IApiProblem.REEXPORTED_MAJOR_VERSION_CHANGE: return "REEXPORTED_MAJOR_VERSION_CHANGE"; //$NON-NLS-1$
case IApiProblem.REEXPORTED_MINOR_VERSION_CHANGE: return "REEXPORTED_MINOR_VERSION_CHANGE"; //$NON-NLS-1$
}
return Util.UNKNOWN_KIND;
}
/**
* Returns the string representation of the API component problem kind
* @param kind
* @return the string of the API component problem kind
*/
public static String getApiComponentResolutionProblemKindName(int kind) {
switch(kind) {
case IApiProblem.API_COMPONENT_RESOLUTION: {
return "API_COMPONENT_RESOLUTION"; //$NON-NLS-1$
}
}
return Util.UNKNOWN_KIND;
}
/**
* Returns the string representation of the API baseline problem kind
* @param kind
* @return the string of the API baseline problem kind
*/
public static String getApiBaselineProblemKindName(int kind) {
switch(kind) {
case IApiProblem.API_BASELINE_MISSING: return "API_BASELINE_MISSING"; //$NON-NLS-1$
}
return Util.UNKNOWN_KIND;
}
/**
* Returns the string representation of the kind of an
* {@link IApiProblem}, given its category
* @param category
* @param kind
* @return the string of the {@link IApiProblem} kind
*/
public static String getProblemKind(int category, int kind) {
switch(category) {
case IApiProblem.CATEGORY_COMPATIBILITY: {
return Util.getDeltaKindName(kind);
}
case IApiProblem.CATEGORY_SINCETAGS: {
return ApiProblem.getTagsProblemKindName(kind);
}
case IApiProblem.CATEGORY_USAGE: {
return ApiProblem.getUsageProblemKindName(kind);
}
case IApiProblem.CATEGORY_VERSION: {
return ApiProblem.getVersionProblemKindName(kind);
}
case IApiProblem.CATEGORY_API_BASELINE: {
return ApiProblem.getApiBaselineProblemKindName(kind);
}
case IApiProblem.CATEGORY_API_COMPONENT_RESOLUTION: {
return ApiProblem.getApiComponentResolutionProblemKindName(kind);
}
}
return Util.UNKNOWN_KIND;
}
/**
* Return the string representation of the flags for a problem
* @param category
* @param flags
* @return the string for the problem flags
*/
public static String getProblemFlagsName(int category, int flags) {
switch(category) {
case IApiProblem.CATEGORY_COMPATIBILITY: {
return Util.getDeltaFlagsName(flags);
}
case IApiProblem.CATEGORY_SINCETAGS:
case IApiProblem.CATEGORY_USAGE:
case IApiProblem.CATEGORY_VERSION:
case IApiProblem.CATEGORY_API_BASELINE:
case IApiProblem.CATEGORY_API_COMPONENT_RESOLUTION: {
switch(flags) {
case IApiProblem.LEAK_EXTENDS: {
return "LEAK_EXTENDS"; //$NON-NLS-1$
}
case IApiProblem.LEAK_FIELD: {
return "LEAK_FIELD"; //$NON-NLS-1$
}
case IApiProblem.LEAK_IMPLEMENTS: {
return "LEAK_IMPLEMENTS"; //$NON-NLS-1$
}
case IApiProblem.LEAK_METHOD_PARAMETER: {
return "LEAK_METHOD_PARAMETER"; //$NON-NLS-1$
}
case IApiProblem.LEAK_CONSTRUCTOR_PARAMETER: {
return "LEAK_CONSTRUCTOR_PARAMETER"; //$NON-NLS-1$
}
case IApiProblem.LEAK_RETURN_TYPE: {
return "LEAK_RETURN_TYPE"; //$NON-NLS-1$
}
case IApiProblem.CONSTRUCTOR_METHOD: {
return "CONSTRUCTOR_METHOD"; //$NON-NLS-1$
}
case IApiProblem.NO_FLAGS: {
return "NO_FLAGS"; //$NON-NLS-1$
}
case IApiProblem.INDIRECT_REFERENCE: {
return "INDIRECT_REFERENCE"; //$NON-NLS-1$
}
case IApiProblem.METHOD: {
return "METHOD"; //$NON-NLS-1$
}
case IApiProblem.FIELD: {
return "FIELD"; //$NON-NLS-1$
}
}
}
}
return Util.UNKNOWN_FLAGS;
}
/**
* Returns the string representation of the element kind of an
* {@link IApiProblem}, given its category
* @param category
* @param kind
* @return the string of the {@link IApiProblem} element kind
*/
public static String getProblemElementKind(int category, int kind) {
switch(category) {
case IApiProblem.CATEGORY_COMPATIBILITY:
case IApiProblem.CATEGORY_SINCETAGS: {
return Util.getDeltaElementType(kind);
}
case IApiProblem.CATEGORY_USAGE:
case IApiProblem.CATEGORY_VERSION:
case IApiProblem.CATEGORY_API_BASELINE:
case IApiProblem.CATEGORY_API_COMPONENT_RESOLUTION: {
return ApiProblem.getDescriptorKind(kind);
}
}
return Util.UNKNOWN_KIND;
}
/**
* Returns a string representation of the category of an api problem
* @param category
* @return the string of the api problem category
*/
public static String getProblemCategory(int category) {
switch(category) {
case IApiProblem.CATEGORY_COMPATIBILITY :
return "COMPATIBILITY"; //$NON-NLS-1$
case IApiProblem.CATEGORY_SINCETAGS :
return "SINCETAGS"; //$NON-NLS-1$
case IApiProblem.CATEGORY_USAGE :
return "USAGE"; //$NON-NLS-1$
case IApiProblem.CATEGORY_VERSION :
return "VERSION"; //$NON-NLS-1$
case IApiProblem.CATEGORY_API_BASELINE :
return "API_BASELINE"; //$NON-NLS-1$
case IApiProblem.CATEGORY_API_COMPONENT_RESOLUTION :
return "API_COMPONENT_RESOLUTION"; //$NON-NLS-1$
default :
return "UNKNOWN_CATEGORY"; //$NON-NLS-1$
}
}
}