| /* ******************************************************************* |
| * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). |
| * 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: |
| * PARC initial implementation |
| * ******************************************************************/ |
| |
| package org.aspectj.weaver; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.text.MessageFormat; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import org.aspectj.bridge.IMessage; |
| import org.aspectj.bridge.ISourceLocation; |
| import org.aspectj.bridge.MessageUtil; |
| import org.aspectj.weaver.tools.Trace; |
| import org.aspectj.weaver.tools.TraceFactory; |
| |
| public class Lint { |
| Map<String, Lint.Kind> kinds = new HashMap<String, Lint.Kind>(); |
| /* private */World world; |
| |
| public final Kind invalidAbsoluteTypeName = new Kind("invalidAbsoluteTypeName", "no match for this type name: {0}"); |
| |
| public final Kind invalidWildcardTypeName = new Kind("invalidWildcardTypeName", "no match for this type pattern: {0}"); |
| |
| public final Kind unresolvableMember = new Kind("unresolvableMember", "can not resolve this member: {0}"); |
| |
| public final Kind typeNotExposedToWeaver = new Kind("typeNotExposedToWeaver", |
| "this affected type is not exposed to the weaver: {0}"); |
| |
| public final Kind shadowNotInStructure = new Kind("shadowNotInStructure", |
| "the shadow for this join point is not exposed in the structure model: {0}"); |
| |
| public final Kind unmatchedSuperTypeInCall = new Kind("unmatchedSuperTypeInCall", |
| "does not match because declaring type is {0}, if match desired use target({1})"); |
| |
| public final Kind unmatchedTargetKind = new Kind("unmatchedTargetKind", "does not match because annotation {0} has @Target{1}"); |
| |
| public final Kind canNotImplementLazyTjp = new Kind("canNotImplementLazyTjp", |
| "can not implement lazyTjp on this joinpoint {0} because around advice is used"); |
| |
| public final Kind multipleAdviceStoppingLazyTjp = new Kind("multipleAdviceStoppingLazyTjp", |
| "can not implement lazyTjp at joinpoint {0} because of advice conflicts, see secondary locations to find conflicting advice"); |
| |
| public final Kind needsSerialVersionUIDField = new Kind("needsSerialVersionUIDField", |
| "serialVersionUID of type {0} needs to be set because of {1}"); |
| |
| public final Kind serialVersionUIDBroken = new Kind("brokeSerialVersionCompatibility", |
| "serialVersionUID of type {0} is broken because of added field {1}"); |
| |
| public final Kind noInterfaceCtorJoinpoint = new Kind("noInterfaceCtorJoinpoint", |
| "no interface constructor-execution join point - use {0}+ for implementing classes"); |
| |
| public final Kind noJoinpointsForBridgeMethods = new Kind( |
| "noJoinpointsForBridgeMethods", |
| "pointcut did not match on the method call to a bridge method. Bridge methods are generated by the compiler and have no join points"); |
| |
| public final Kind enumAsTargetForDecpIgnored = new Kind("enumAsTargetForDecpIgnored", |
| "enum type {0} matches a declare parents type pattern but is being ignored"); |
| |
| public final Kind annotationAsTargetForDecpIgnored = new Kind("annotationAsTargetForDecpIgnored", |
| "annotation type {0} matches a declare parents type pattern but is being ignored"); |
| |
| public final Kind cantMatchArrayTypeOnVarargs = new Kind("cantMatchArrayTypeOnVarargs", |
| "an array type as the last parameter in a signature does not match on the varargs declared method: {0}"); |
| |
| public final Kind adviceDidNotMatch = new Kind("adviceDidNotMatch", "advice defined in {0} has not been applied"); |
| |
| public final Kind invalidTargetForAnnotation = new Kind("invalidTargetForAnnotation", |
| "{0} is not a valid target for annotation {1}, this annotation can only be applied to {2}"); |
| |
| public final Kind elementAlreadyAnnotated = new Kind("elementAlreadyAnnotated", |
| "{0} - already has an annotation of type {1}, cannot add a second instance"); |
| |
| public final Kind runtimeExceptionNotSoftened = new Kind("runtimeExceptionNotSoftened", |
| "{0} will not be softened as it is already a RuntimeException"); |
| |
| public final Kind uncheckedArgument = new Kind("uncheckedArgument", |
| "unchecked match of {0} with {1} when argument is an instance of {2} at join point {3}"); |
| |
| public final Kind uncheckedAdviceConversion = new Kind("uncheckedAdviceConversion", |
| "unchecked conversion when advice applied at shadow {0}, expected {1} but advice uses {2}"); |
| |
| public final Kind noGuardForLazyTjp = new Kind("noGuardForLazyTjp", |
| "can not build thisJoinPoint lazily for this advice since it has no suitable guard"); |
| |
| public final Kind noExplicitConstructorCall = new Kind("noExplicitConstructorCall", |
| "inter-type constructor does not contain explicit constructor call: field initializers in the target type will not be executed"); |
| |
| public final Kind aspectExcludedByConfiguration = new Kind("aspectExcludedByConfiguration", |
| "aspect {0} exluded for class loader {1}"); |
| |
| public final Kind unorderedAdviceAtShadow = new Kind("unorderedAdviceAtShadow", |
| "at this shadow {0} no precedence is specified between advice applying from aspect {1} and aspect {2}"); |
| |
| public final Kind swallowedExceptionInCatchBlock = new Kind("swallowedExceptionInCatchBlock", |
| "exception swallowed in catch block"); |
| |
| public final Kind calculatingSerialVersionUID = new Kind("calculatingSerialVersionUID", |
| "calculated SerialVersionUID for type {0} to be {1}"); |
| |
| public final Kind nonReweavableTypeEncountered = new Kind("nonReweavableTypeEncountered", |
| "class '{0}' is already woven and has not been built in reweavable mode"); |
| |
| // there are a lot of messages in the cant find type family - I'm defining an umbrella lint warning that |
| // allows a user to control their severity (for e.g. ltw or binary weaving) |
| public final Kind cantFindType = new Kind("cantFindType", "{0}"); |
| |
| public final Kind cantFindTypeAffectingJoinPointMatch = new Kind("cantFindTypeAffectingJPMatch", "{0}"); |
| |
| public final Kind advisingSynchronizedMethods = new Kind("advisingSynchronizedMethods", |
| "advice matching the synchronized method shadow ''{0}'' will be executed outside the lock rather than inside (compiler limitation)"); |
| |
| public final Kind mustWeaveXmlDefinedAspects = new Kind( |
| "mustWeaveXmlDefinedAspects", |
| "XML Defined aspects must be woven in cases where cflow pointcuts are involved. Currently the include/exclude patterns exclude ''{0}''"); |
| |
| public final Kind cannotAdviseJoinpointInInterfaceWithAroundAdvice = new Kind( |
| "cannotAdviseJoinpointInInterfaceWithAroundAdvice", |
| "The joinpoint ''{0}'' cannot be advised and is being skipped as the compiler implementation will lead to creation of methods with bodies in an interface (compiler limitation)"); |
| |
| /** |
| * Indicates an aspect could not be found when attempting reweaving. |
| */ |
| public final Kind missingAspectForReweaving = new Kind("missingAspectForReweaving", |
| "aspect {0} cannot be found when reweaving {1}"); |
| |
| private static Trace trace = TraceFactory.getTraceFactory().getTrace(Lint.class); |
| |
| public Lint(World world) { |
| if (trace.isTraceEnabled()) { |
| trace.enter("<init>", this, world); |
| } |
| this.world = world; |
| if (trace.isTraceEnabled()) { |
| trace.exit("<init>"); |
| } |
| } |
| |
| public void setAll(String messageKind) { |
| if (trace.isTraceEnabled()) { |
| trace.enter("setAll", this, messageKind); |
| } |
| setAll(getMessageKind(messageKind)); |
| if (trace.isTraceEnabled()) { |
| trace.exit("setAll"); |
| } |
| } |
| |
| private void setAll(IMessage.Kind messageKind) { |
| for (Kind kind : kinds.values()) { |
| kind.setKind(messageKind); |
| } |
| } |
| |
| public void setFromMap(Map<String,String> lintOptionsMap) { |
| for (String key: lintOptionsMap.keySet()) { |
| String value = lintOptionsMap.get(key); |
| Kind kind = kinds.get(key); |
| if (kind == null) { |
| MessageUtil.error(world.getMessageHandler(), WeaverMessages.format(WeaverMessages.XLINT_KEY_ERROR, key)); |
| } else { |
| kind.setKind(getMessageKind(value)); |
| } |
| } |
| } |
| |
| public void setFromProperties(File file) { |
| if (trace.isTraceEnabled()) { |
| trace.enter("setFromProperties", this, file); |
| } |
| InputStream s = null; |
| try { |
| s = new FileInputStream(file); |
| setFromProperties(s); |
| } catch (IOException ioe) { |
| MessageUtil.error(world.getMessageHandler(), |
| WeaverMessages.format(WeaverMessages.XLINT_LOAD_ERROR, file.getPath(), ioe.getMessage())); |
| } finally { |
| if (s != null) { |
| try { |
| s.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| } |
| } |
| |
| if (trace.isTraceEnabled()) { |
| trace.exit("setFromProperties"); |
| } |
| } |
| |
| public void loadDefaultProperties() { |
| InputStream s = getClass().getResourceAsStream("XlintDefault.properties"); |
| if (s == null) { |
| MessageUtil.warn(world.getMessageHandler(), WeaverMessages.format(WeaverMessages.XLINTDEFAULT_LOAD_ERROR)); |
| return; |
| } |
| try { |
| setFromProperties(s); |
| } catch (IOException ioe) { |
| MessageUtil.error(world.getMessageHandler(), |
| WeaverMessages.format(WeaverMessages.XLINTDEFAULT_LOAD_PROBLEM, ioe.getMessage())); |
| } finally { |
| try { |
| s.close(); |
| } catch (IOException ioe) { |
| // ignore |
| } |
| } |
| |
| } |
| |
| private void setFromProperties(InputStream s) throws IOException { |
| Properties p = new Properties(); |
| p.load(s); |
| setFromProperties(p); |
| } |
| |
| @SuppressWarnings("rawtypes") |
| public void setFromProperties(Properties properties) { |
| for (Iterator i = properties.entrySet().iterator(); i.hasNext();) { |
| Map.Entry entry = (Map.Entry) i.next(); |
| Kind kind = kinds.get(entry.getKey()); |
| if (kind == null) { |
| MessageUtil.error(world.getMessageHandler(), WeaverMessages.format(WeaverMessages.XLINT_KEY_ERROR, entry.getKey())); |
| } else { |
| kind.setKind(getMessageKind((String) entry.getValue())); |
| } |
| } |
| } |
| |
| public Collection<Kind> allKinds() { |
| return kinds.values(); |
| } |
| |
| public Kind getLintKind(String name) { |
| return kinds.get(name); |
| } |
| |
| // temporarily suppress the given lint messages |
| public void suppressKinds(Collection<Kind> lintKind) { |
| if (lintKind.isEmpty()) { |
| return; |
| } |
| for (Kind k : lintKind) { |
| k.setSuppressed(true); |
| } |
| } |
| |
| // remove any suppression of lint warnings in place |
| public void clearAllSuppressions() { |
| for (Kind k : kinds.values()) { |
| k.setSuppressed(false); |
| } |
| } |
| |
| public void clearSuppressions(Collection<Lint.Kind> lintKinds) { |
| for (Kind k : lintKinds) { |
| k.setSuppressed(false); |
| } |
| } |
| |
| private IMessage.Kind getMessageKind(String v) { |
| if (v.equals("ignore")) { |
| return null; |
| } else if (v.equals("warning")) { |
| return IMessage.WARNING; |
| } else if (v.equals("error")) { |
| return IMessage.ERROR; |
| } |
| |
| MessageUtil.error(world.getMessageHandler(), WeaverMessages.format(WeaverMessages.XLINT_VALUE_ERROR, v)); |
| return null; |
| } |
| |
| public Kind fromKey(String lintkey) { |
| return kinds.get(lintkey); |
| } |
| |
| public class Kind { |
| private final String name; |
| private final String message; |
| private IMessage.Kind kind = IMessage.WARNING; |
| private boolean isSupressed = false; // by SuppressAjWarnings |
| |
| public Kind(String name, String message) { |
| this.name = name; |
| this.message = message; |
| kinds.put(this.name, this); |
| } |
| |
| public void setSuppressed(boolean shouldBeSuppressed) { |
| this.isSupressed = shouldBeSuppressed; |
| } |
| |
| public boolean isEnabled() { |
| return (kind != null) && !isSupressed(); |
| } |
| |
| private boolean isSupressed() { |
| // can't suppress errors! |
| return isSupressed && (kind != IMessage.ERROR); |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public IMessage.Kind getKind() { |
| return kind; |
| } |
| |
| public void setKind(IMessage.Kind kind) { |
| this.kind = kind; |
| } |
| |
| public void signal(String info, ISourceLocation location) { |
| if (kind == null) { |
| return; |
| } |
| |
| String text = MessageFormat.format(message, new Object[] { info }); |
| text += " [Xlint:" + name + "]"; |
| world.getMessageHandler().handleMessage(new LintMessage(text, kind, location, null, getLintKind(name))); |
| } |
| |
| public void signal(String[] infos, ISourceLocation location, ISourceLocation[] extraLocations) { |
| if (kind == null) { |
| return; |
| } |
| |
| String text = MessageFormat.format(message, (Object[]) infos); |
| text += " [Xlint:" + name + "]"; |
| world.getMessageHandler().handleMessage(new LintMessage(text, kind, location, extraLocations, getLintKind(name))); |
| } |
| |
| } |
| |
| } |