/* ******************************************************************* * 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 v 2.0 * which accompanies this distribution and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt * * 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.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 kinds = new HashMap<>(); /* 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 final Trace trace = TraceFactory.getTraceFactory().getTrace(Lint.class); public Lint(World world) { if (trace.isTraceEnabled()) { trace.enter("", this, world); } this.world = world; if (trace.isTraceEnabled()) { trace.exit(""); } } 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 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); } public void setFromProperties(Properties properties) { for (Map.Entry entry : properties.entrySet()) { 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 allKinds() { return kinds.values(); } public Kind getLintKind(String name) { return kinds.get(name); } // temporarily suppress the given lint messages public void suppressKinds(Collection 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 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))); } } }