Git Product home page Git Product logo

mutabilitydetector's Introduction

Latest Version Email Join the chat at https://gitter.im/MutabilityDetector/main Build Status

What is Mutability Detector?

Mutability Detector is designed to analyse Java classes and report on whether instances of a given class are immutable. It can be used:

  • In a unit test, with an assertion like assertImmutable(MyClass.class). Is your class actually immutable? What about after that change you just made?
  • As a FindBugs plugin. Those classes you annotated with @Immutable, are they actually?
  • At runtime. Does your API require being given immutable objects?
  • From the command line. Do you want to quickly run Mutability Detector over an entire code base?

Why Try To Detect Mutability?

Developing classes to be immutable has several benefits. An immutable object is one which cannot be changed once it is constructed. While writing concurrent programs, using immutable objects can greatly simplify complex systems, as sharing an object across threads is much safer. There are a few rules for what makes an object immutable, and it is easy to break the rules and render the object unsafe. This could lead to subtle, hard-to-detect bugs which could lower the integrity of the system. Using an automated tool to recognise mutability where it's not intended can reduce the complexity of writing immutable classes.

Mutability Detector analyses on the strict side, very few classes are found to be perfectly immutable, for instance, java.lang.String and java.lang.Integer are not immutable because of a non-final field, and primitive array field, respectively. Mutability Detector will not be released under a 1.0 version until these cases can be correctly analysed.

If this sounds like it may be interesting or useful to you, continue reading for more information on getting started. You may also want to take a look at the Mutability Detector Blog.

Getting Started

To use Mutability Detector directly, either from the command line, at runtime in your application, or as part of your unit tests, grab the jar available from Maven Central. Or you can declare it in your Maven-compatible build tool, with the following coordinates:

<dependency>
    <groupId>org.mutabilitydetector</groupId>
    <artifactId>MutabilityDetector</artifactId>
    <version>[latest version here]</version>
    <scope>test</scope>
</dependency>

Latest Version

Using Mutability Detector in Unit Testing

Just add MutabilityDetector to your unit testing classpath. Adding your first assertion is as simple as:

import static org.mutabilitydetector.unittesting.MutabilityAssert.assertImmutable;

@Test public void checkMyClassIsImmutable() {
    assertImmutable(MyClass.class); 
}

Though it is possible (or likely) that you will have to configure the assertion to deal with any false positives that arise. See the JavaDoc on MutabilityAssert for further information.

Using Mutability Detector from the Command Line

An example of how to run it is probably the most useful. If you want to analyse MyCodebase.jar use:

java -jar MutabilityDetector.jar -classpath path/to/MyCodebase.jar

Mutability Detector can handle jars as seen above, or directories of class files (thanks go to the authors of classpath-explorer). So if your codebase was in the filesystem as directories and .class files, and the directory MyCodebase was the root of that, you could run:

java -jar MutabilityDetector.jar -classpath path/to/MyCodebase

The output is a list of the analysed classes against the result of asking "Is immutable?", ie. IMMUTABLE, NOT_IMMUTABLE, EFFECTIVELY_IMMUTABLE.

Execute java -jar MutabilityDetector.jar --help for a complete listing of the command line options.

Using Mutability Detector within Your Application

It is possible to use Mutability Detector at runtime. For example, consider if you have a library which requires that objects passed to it are immutable. On receiving such an object, you can ask Mutability Detector if it is actually immutable.

Check out the code snippet in this example, which shows correct usage against trunk code.

FindBugs Plugin

To have Mutability Detector inspect your classes during a FindBugs analysis, grab the MutabilityDetector4FindBugs jar, and configure it to be picked up by FindBugs during a normal analysis, as described here.

Mutability Detector will perform it's analysis on any classes annotated with @Immutable.

MutabilityDetector4FindBugs is also available from Maven Central, with the following coordinates:

<dependency>
    <groupId>org.mutabilitydetector</groupId>
    <artifactId>MutabilityDetector4FindBugs</artifactId>
    <version>[latest version here]</version>
    <scope>test</scope>
</dependency>

MutabilityDetector4FindBugs Latest Version

mutabilitydetector's People

Contributors

badgersow avatar bharatbhasin avatar civild avatar dependabot-preview[bot] avatar dependabot[bot] avatar emmahastings avatar fma1 avatar grommitz avatar grundlefleck avatar iweiss avatar jagan387 avatar kwahsog avatar l0s avatar lasombra avatar marcgs avatar moelkhidir avatar neomatrix369 avatar nic314 avatar pschoffer avatar ricemery avatar sband avatar seanjreilly avatar snyk-bot avatar stephan202 avatar sullis avatar talflon avatar vestigej avatar vik4es avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mutabilitydetector's Issues

OutOfMemoryError in PermGen space

Original author: [email protected] (September 26, 2010 17:42:22)

The problem can be reproduced using Sun JDK 1.6.12, running MutabilityDetector on rt.jar.

This can be worked around by using the VM argument "-XX:MaxPermSize=256m", however, it just shouldn't happen.

The likely suspect is the AbstractTypeToFieldChecker, which loads classes to find out if an assigned type is abstract or not. This could probably be done a lot more efficiently.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=9

Migrate from Google Code to GitHub

Original author: [email protected] (July 19, 2012 20:43:27)

It has been suggested that I move the project from googlecode to GitHub to improve the likelihood of collaboration.

I'm open to the idea, but a bit wary of the problems it may cause:

  • transferring wiki/issues etc
  • confusion for users having two sites (or the problem of closing the google code version altogether and having old links not work)
  • safely migrating version control history

Intended benefits are:

  • increased collaboration, GitHub provides a much easier way of suggesting improvements by way of pull requests
  • would be easier to stop using a nested scm structure (googlecode project holds 3 projects in one)

I'm inclined to be a bit lazy about this, and maybe see if there is more desire for collaborating.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=28

Possible issue with java.time.Instant

Hi,

I'm trying to add a test to ensure that a class is mutable, and the mutability detector seems to be crashing.

I've put the stack trace in a gist.

The codebase is an open source Java 8 project, so you should be able to reproduce the issue fairly easily yourself. I've got it on its own branch (mutability-detector-bug) and the commit that adds the failing test is 184625f44e7d39f21075ab43824c2eb3818293d9.

A quick look at the stack trace seems to indicate some sort of issue with java.time.Instant and ASM. As you can see from the file dependencies.gradle, the project is using version 0.9.1, which IIRC fixed some java 8 issues (and I'm using the detector in other places in the codebase without issue).

If you need any help debugging the issue, please let me know and I'll help as much as I can.

Immutable class is being reported as mutable

Original author: [email protected] (April 28, 2012 19:44:32)

This class is immutable (note the defensive copies on Date constructor set and on get):

public final class Claim {
public final double amount;
private final Date failureDate;

Claim(double amount, Date failureDate) {
    this.amount = amount;
    this.failureDate = new Date(failureDate.getTime());
}

public Date getFailureDate() {
    return new Date(failureDate.getTime());
}

}

It should be reported as immutable, but Mutability Detector incorrectly says it's NOT_IMMUTABLE.

For example, this class is analysed as immutable, and is essentially the same:

public final class Claim {
public final double amount;
private final long failureTime;

Claim(double amount, long failureTime) {
    this.amount = amount;
    this.failureTime = failureTime;
}

public Date getFailureDate() {
    return new Date(failureTime);
}

}

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=27

Setting private field on a different instance of self type renders class as mutable (e.g. BigDecimal)

Original author: [email protected] (August 10, 2010 00:44:29)

The following class (simplifying the characteristics of java.math.BigDecimal) is reported as mutable:

<verbatim>
public class ImmutableButSetsPrivateFieldOfInstanceOfSelf {

private int myField = 0;

public ImmutableButSetsPrivateFieldOfInstanceOfSelf setPrivateFieldOnInstanceOfSelf() {
    ImmutableButSetsPrivateFieldOfInstanceOfSelf i = new ImmutableButSetsPrivateFieldOfInstanceOfSelf();
    i.myField = 10; // method now considered a 'setter' method
    return i;
}

}
</verbatim>

The class above is immutable. It is reported as mutable because the field 'myField' is reassigned outwith the constructor. The analysis is too naive, not recognising that the assignment of myField is not on the 'this' instance.

The most general solution would be to check that the assignment cannot be made on an instance which could be seen to change by a client. This includes the this instance (after the reference is published), but it would also include instances passed from outwith the this instance. In the above example, an instance cannot be seen to change because the variable i is declared in local scope, and is not visible before the field is set.

This pattern occurs several times in BigDecimal. In some cases the assignment is made on local BigDecimals, in others it is within private methods which are invoked before the reference is published.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=8

An analysis error will occur when field is reassigned to newed up object.

Original author: [email protected] (April 26, 2011 21:14:11)

The following source code:

{{{
public class MutableByAssigningFieldToNewedUpObject {
private String changeMe = "Begin like this";

public void reassignMyField() {
    changeMe = new String(&quot;Haha!&quot;);
}

}
}}}

Will cause an unhandled error during analysis (due to an NPE from the SetterMethodChecker).

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=14

Possible Java 8 issue

I'm testing that each value in an enum is immutable. Here's a rough example:

    @Test
    public void enumInstance_shouldBeEffectivelyImmutable() throws Exception {
        assertInstancesOf(MyEnum.FOO.getClass(), areImmutable());
    }

Compiling and running in Java 7 works with no problems. However, when I try the same thing using Java 8 I get a big nasty error (stack trace included below).

org.mutabilitydetector.checkers.MutabilityAnalysisException: 
An unhandled error occurred. Please read message at end of this output.

Class being analysed: uk.gov.gds.performance.collector.CollectorLogMessage
Checker that failed: CanSubclassChecker
Classes analysed so far:

An unhandled error occurred. This is probably my fault, not yours, and I am sorry.
I'd love to get an opportunity to fix this, please report as an issue at:
 https://github.com/MutabilityDetector/MutabilityDetector/issues/ 
Pasting in this error message and stack trace, and if possible, 
information about the code causing the error. 
For example, one of: 
    .class files (preferably with source);
    compilable .java files; 
    a jar (again preferably with source);
    or, if your project is open source, information on where I can get the code from
        (I'm happy to checkout and build your project in order to investigate the error).

Apologies, and thank you for using Mutability Detector.


    at org.mutabilitydetector.checkers.UnhandledExceptionBuilder.unhandledException(UnhandledExceptionBuilder.java:54)
    at org.mutabilitydetector.checkers.CheckerRunner.attemptRecovery(CheckerRunner.java:79)
    at org.mutabilitydetector.checkers.CheckerRunner.run(CheckerRunner.java:66)
    at org.mutabilitydetector.checkers.AllChecksRunner.runCheckers(AllChecksRunner.java:65)
    at org.mutabilitydetector.ThreadUnsafeAnalysisSession.requestAnalysis(ThreadUnsafeAnalysisSession.java:118)
    at org.mutabilitydetector.ThreadUnsafeAnalysisSession.resultFor(ThreadUnsafeAnalysisSession.java:104)
    at org.mutabilitydetector.unittesting.MutabilityAsserter.getResultFor(MutabilityAsserter.java:184)
    at org.mutabilitydetector.unittesting.MutabilityAsserter.assertInstancesOf(MutabilityAsserter.java:109)
    at org.mutabilitydetector.unittesting.MutabilityAssert.assertInstancesOf(MutabilityAssert.java:658)
    at com.equalexperts.logging.LogMessageContractTest.enumInstance_shouldBeEffectivelyImmutable(LogMessageContractTest.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runners.Suite.runChild(Suite.java:127)
    at org.junit.runners.Suite.runChild(Suite.java:26)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runners.Suite.runChild(Suite.java:127)
    at org.junit.runners.Suite.runChild(Suite.java:26)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:202)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.IllegalArgumentException
    at org.mutabilitydetector.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:167)
    at org.mutabilitydetector.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:153)
    at org.mutabilitydetector.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:468)
    at org.mutabilitydetector.checkers.CheckerRunner.analyseFromDefaultClassLoader(CheckerRunner.java:99)
    at org.mutabilitydetector.checkers.CheckerRunner.run(CheckerRunner.java:63)
    ... 49 more

Analysis causes classes to be loaded

Original author: [email protected] (March 03, 2012 17:27:32)

Parts of the analysis use ASM's SimpleVerifier class, which attempts to load classes to perform "isAssignableFrom" logic. Currently MutabilityDetector goes to some effort to ensure a specific classloader is used, which is aware of the classpath specified by the user (e.g. from the cli, or as part of the FindBugs plugin).

It would be nice to remove this complexity by performing the "isAssignableFrom" logic within static analysis of the bytecode, without having to load the class. Apart from the reduction in complexity, it would probably mean the analysis would be faster as well.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=24

Maven compiler plugin-version issue (version 2.0.2 in pom.xml)

When building the MutabilityDetector project via CLI (to investigate and fix issue #33), due to the maven compiler plugin version number of 2.0.2 in the pom.xml the below message was returned:

https://gist.github.com/4420590

Current pom.xml setting (see https://github.com/MutabilityDetector/MutabilityDetector/blob/master/pom.xml):

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.0.2</version>         <===== currently set to 2.0.2 is that a requirement?
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>

Changing the pom.xml to the below fixes the issue:

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>         <===== the version of the maven complier plugin available on my system
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>

In contrast the pom.xml in ClientOfMutabilityDetector does not have this setting, see https://github.com/MutabilityDetector/ClientOfMutabilityDetector/blob/master/pom.xml, and it builds fine using the 2.3.2 maven compiler plugin from both the CLI and from within Eclipse.

Should be able to specify which classes to report on from the command line.

Original author: [email protected] (July 24, 2010 19:55:54)

Currently the command line allows specifying a '-match' argument. This will will report on all the classes which affect the result for matched classes. There is also the '-report' flag, which will report all results which match the given result. There should be a third option which will report only those classes which match a list of given class names.

This should probably work by reading in a list of class names from a text file. E.g.:
java -jar MutabilityDetector.jar --report-classes classnames.txt

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=7

No obvious way to use Collections.umodifiable*

Original author: [email protected] (March 07, 2012 15:32:55)

What steps will reproduce the problem?

I have a class that has just one field, and that field can't be changed, and it's assigned in the constructor to be an immutable colllection. I don't have an obvious way though to prove that with this. Obviously, static analysis of a class may be difficult/impossible without the actual instance being created, but I didn't see how to test against that. I also don't see a way from Collections that I can even get hold of the unmodifable classes (private for the unmodifable map) so that I could write a custom matcher. Thoughts?

With a class that has:

private final Map<String,Object> propMap;
public ImmutableConfiguration(AbstractConfiguration origConfiguration) {

    LOG.debug(&quot;&gt;&gt;&gt; ImmutableConfiguration&quot;);

    Map store = new HashMap();
    //we need the variables interpolated, which doesn't come at the getProperty level
    Configuration interpolated = origConfiguration.interpolatedConfiguration();
    final Iterator keyIter = interpolated.getKeys();
    while (keyIter.hasNext()) {
        String key = (String) keyIter.next();
        store.put(key,interpolated.getProperty(key));
    }
    this.propMap = Collections.unmodifiableMap(store);
    LOG.debug(&quot;&lt;&lt;&lt; ImmutableConfiguration&quot;);
}

}

I'll get
Field can have an abstract type (java.util.Map) assigned to it. [Field: propMap, Class: com.angel.config.ImmutableConfiguration]

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=25

Getting started page for the Wiki (for developers and users)

Issue #33 lead to the below discussion about a "How to get started page for both Developers and Users of Mutability Detector ?"

Initial suggestion from @neomatrix369

Suggestions:

  1. Should we have a wiki page titled 'Getting started...' for both users and developers of MD and it points to the README.md file and the How to Contribute link pages of the Wiki respectively?
  2. Can we put anything on the README,md and wiki pages from what I have experienced?
  3. Also link to your blogs and videos (handy) from the wiki / readme.md pages.

Response from @Grundlefleck

You mentioned elsewhere, perhaps in an email, about trying to find a better way of helping devs get started without running into the issue you saw. I agree, could you raise an issue and propose a fix? You'll have better perspective as you were coming fresh-faced to the project. I'm thinking of something like having a GETTING_STARTED.md in the root directory of the git checkout, but open to more novel suggestions :)

In essence the below Wiki page was referred to, where the changes will take place: https://github.com/MutabilityDetector/MutabilityDetector/wiki

Also consider updating to bring them in sync: http://mutabilitydetector.github.com/MutabilityDetector/

Audit all code locations emitted and recommend whether it should be changed

In issue #43 , one of the subtasks is 'an audit of all existing checkers, to make sure that they provide the most appropriate location for the reason (e.g. for reassigned fields, do we point to the field, or where it's reassigned?)'.

I think this is large enough to split into it's own task.

I suggest the following:

  1. find all the potential errors that are raised across all checkers (you can do this by finding all callers of AbstractMutabilityChecker#setResult -- there's 19 references across 12 subclasses)
  2. write a test that will expose each one (this will require a fair bit of investigation, and possibly a debugger and/or a coverage tool)
  3. recommend to the mailing list which ones you feel already have the best location, and which ones could be improved, and how.

The test written in part 2 could potentially become the automated acceptance test.

Allow writing a single test case which will scan the current classpath for all @Immutable classes

Currently, if you want to start using Mutability Detector on your project, and you already have a lot of classes marked as @Immutable, you can either:

  • use the FindBugs plugin to automatically detect them, in which case, you can't configure the assertion to suppress false positives
  • add a unit test for every class, in which case, you have to spend a lot of tedious time writing new test methods.

I would like to find a solution which offers the best of both worlds: to be able to quickly check all your immutable classes, but which still allows flexible configuration for suppressing false positives.

Currently I think we could do something where:

  • a user configures one assertion in a unit test
  • the test scans the classpath for @Immutable classes and analyses them, reporting errors from all classes
  • ... excluding classes which are being tested in another method, with custom suppressions.

This could possibly use a library like http://scannotation.sourceforge.net/ or something similar, to do the scanning. I don't know yet how this method could exclude classes which are being tested elsewhere. Perhaps we would need to get creative.

Improve error message for unwrapped Collections

Currently the error message for a Class having a collection as a field which is initialized in constructor is: "Attempts to wrap mutable collection type using a non-whitelisted unmodifiable wrapper method". This is misleading, since in this case nothing is getting wrapped at all.

The goal of this issue is to improve this error message to something like "Not wrapped collection type". This mutability reason is detected by MutableTypeToFieldChecker.

Here a test which asserts the current error message

   public final static class ClassNotWrappingCollection {
        private final Collection<String> collection;

        public ClassNotWrappingCollection(Collection<String> collection) {
            this.collection = collection;
        }
    }

    @Test
    public void isImmutableMutableTypeToField_ClassNotWrappingCollection() throws Exception {
        try {
            assertImmutable(ClassNotWrappingCollection.class);
            fail("Error should be thrown");
        } catch (MutabilityAssertionError e) {
            assertThat(e.getMessage(), is("\n"+
                    "Expected: org.mutabilitydetector.ErrorLocationTest$ClassNotWrappingCollection to be IMMUTABLE\n" +
                    "     but: org.mutabilitydetector.ErrorLocationTest$ClassNotWrappingCollection is actually NOT_IMMUTABLE\n" +
                    "    Reasons:\n" +
                    "        Attempts to wrap mutable collection type using a non-whitelisted unmodifiable wrapper method. [Field: collection, Class: org.mutabilitydetector.ErrorLocationTest$ClassNotWrappingCollection]\n" +
                    "    Allowed reasons:\n" +
                    "        None."));
        }
    }

Minor typo in JavaDocs - a

Original author: [email protected] (November 21, 2012 16:19:19)

What steps will reproduce the problem?

  1. View the JavaDocs at https://mutability-detector.googlecode.com/svn/trunk/MutabilityDetector/trunk/javadoc/latest/org/mutabilitydetector/unittesting/MutabilityAssert.html
  2. Read the section on "Configuring the assertion"
  3. Read sample code that says "assertInstancesOf(MyClassWhereTheFieldsAreNotFinal.class, areImmutable());"

What is the expected output? What do you see instead?

I think it should be using areEffectivelyImmutable - so it should look like this:

assertInstancesOf(MyClassWhereTheFieldsAreNotFinal.class, areEffectivelyImmutable());

What version of the product are you using? On what operating system?

Javadocs on project site.

Please provide any additional information below.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=31

Can Subclass checking is incorrect when inner class constructs instance of outer, immutable class

The following class is considered mutable:

public class OnlyPrivateConstructors {
    private final String field;

    private OnlyPrivateConstructors(String field) {
        this.field = field;
    }

    public String getField() {
        return field;
    }

    public static class Builder {
        public OnlyPrivateConstructors build() {
            return new OnlyPrivateConstructors("hi");
        }
    }
}

With the message:

Expected: org.mutabilitydetector.issues.OnlyPrivateConstructors to be IMMUTABLE
     but: org.mutabilitydetector.issues.OnlyPrivateConstructors is actually NOT_IMMUTABLE
    Reasons:
        Can be subclassed, therefore parameters declared to be this type could be mutable subclasses at runtime. [Class: org.mutabilitydetector.issues.OnlyPrivateConstructors]
    Allowed reasons:
        None.

If the call to new OnlyPrivateConstructors() is commented out, the analysis correctly calls this class immutable. This pattern is a common way of implementing the Builder pattern (as described in Effective Java, iirc). It should not render the outer class as immutable.

Correctly analyse array field mutation

Original author: [email protected] (November 15, 2011 22:34:46)

Currently the following class will be called mutable:

public final class ImmutableButHasUnmodifiedArrayAsField {
private final int[] unmodifiedArray;

public ImmutableButHasUnmodifiedArrayAsField() {
    this.unmodifiedArray = new int[] { 3, 14 };
}

public int getWhole() {
    return unmodifiedArray[0];
}

public int getFraction() {
    return unmodifiedArray[1];
}

}

However, this class is immutable (effectively immutable if the field is not marked final). It is ensuring exclusive access to the mutable components (including the elements of the array, which would not be true if replacing int[] with a mutable type, e.g. List<>[]). An update to the analysis should allow such a class under the following rules:

  1. the array is not passed into constructor as a parameter
  2. the array does not escape (but consider if the "best guess" analysis of the escaped this reference checker will be good enough, if not, probably should abort).
  3. the type of array is immutable
  4. the references in the array are never changed, e.g. myArray[1] = 42

(Depending on the success of this attempt, the same rules could extend to any mutable type used as a field, except replace #4 with 'a mutating method is never called')

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=18

Consolidate similar mutability reasons

There are a few cases where similar or redundant mutability reasons are reported Examples are:

a) ABSTRACT_TYPE_INHERENTLY_MUTABLE + CAN_BE_SUBCLASSED for abstract classes
b) PUBLISHED_NON_FINAL_FIELD + NON_FINAL_FIELD for published non final fields
c) FIELD_CAN_BE_REASSIGNED + NON_FINAL_FIELD for fields which are modified in a method

The goal of this issue is to:

1- Detect all cases where redundant mutability reasons are reported
2- Analyze a mechanism how to consolidate them and present a less verbose error message to the user. It should still be possible to disable checks granularly using AllowedReasons (for instance FIELD_CAN_BE_REASSIGNED should be still shown for c) if final fields are allowed)
3- Implement solution

Allow clicking through to source of mutability reason

Currently, when a unit test fails, it displays all the reasons a class is mutable. Each reason is printed with a location, the 'primary' source of mutability, for example, [Field: hash, Class: java.lang.String] for the hash field that can be reassigned. A user will have to read this then navigate to the file and field themselves.

Text output in test failure shown here:

current_source_code_location_arrow

We can do more to make it easier to find the source of mutability. At least two of the three major IDEs (Eclipse and Intellij, not checked NetBeans) have functionality that interprets elements of a stack trace, to allow clicking through to source.

Like here:

Eclipse:
eclipse_linking_to_source_arrow

IntelliJ:
intellij_linking_to_source_arrow

This is achieved by having a string which matches a particular format, like:
at java.lang.String.<init>(String.java:105)
(the "at", with that casing, is significant).

We could take advantage of this trick in the IDEs to allow us to print locations which are clickable.

This issue would represent three bits of work:

  • making sure that every reason also prints a location which matches this format, such that it can be clicked through
  • an audit of all existing checkers, to make sure that they provide the most appropriate location for the reason (e.g. for reassigned fields, do we point to the field, or where it's reassigned?)
  • potentially doing extra bytecode analysis, to find the class, method, and line number of the most suitable location for the reason

Unit tests do not work with sbt

With a sbt-based Scala project, a unit test like so:

@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class ImmutabilityTests extends FunSuite with ShouldMatchers {

    test("be immutable") {
        MutabilityAssert.assertImmutable(classOf[SomeCaseClass])
    }
 }

The test will work under IDEs, but will not work with "sbt test" from the command line. The standard Mutability Detector exception will be thrown, which will contain the trace:

[info] Cause: java.io.IOException: Class not found
[info] at org.mutabilitydetector.repackaged.org.objectweb.asm.ClassReader.readClass(ClassReader.java:484)
[info] at org.mutabilitydetector.repackaged.org.objectweb.asm.ClassReader.(ClassReader.java:468)
[info] at org.mutabilitydetector.checkers.CheckerRunner.analyseFromDefaultClassLoader(CheckerRunner.java:102)

ClassNotFoundException when Guava is not on the classpath

With the currently released version (0.9.3) I get the following exception:

java.lang.ExceptionInInitializerError
    at org.mutabilitydetector.unittesting.MutabilityAssert.<clinit>(MutabilityAssert.java:658)
    ...
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.mutabilitydetector.checkers.MutabilityAnalysisException: Error in configuration: Class not  found: com.google.common.collect.Lists
    at org.mutabilitydetector.ConfigurationBuilder.rethrow(ConfigurationBuilder.java:447)
    at org.mutabilitydetector.ConfigurationBuilder.hardcodeValidCopyMethod(ConfigurationBuilder.java:432)
    at org.mutabilitydetector.config.GuavaConfiguration.configure(GuavaConfiguration.java:37)
    at org.mutabilitydetector.ConfigurationBuilder.build(ConfigurationBuilder.java:148)
    at org.mutabilitydetector.Configurations.<clinit>(Configurations.java:39)
    ... 25 more
Caused by: java.lang.ClassNotFoundException: com.google.common.collect.Lists
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:260)
    at org.mutabilitydetector.ConfigurationBuilder.hardcodeValidCopyMethod(ConfigurationBuilder.java:424)
    ... 28 more

With version 0.9.2 the exception does not occur.

Matching effectivelyImmutable classes does not permit allowing reasons for mutability.

Original author: [email protected] (November 23, 2011 21:00:04)

What steps will reproduce the problem?

  1. Write a class that is mutable for a single reason, e.g. by allowing subclassing, and effectively immutable by having a non-final field
  2. Write a test that it is effectively immutable, allowing subclassing
  3. Run test, it will fail

What is the expected output? What do you see instead?
The test should pass, because it is effectively immutable, and the single reason for it being mutable has been allowed. The test should work without supplying any additional allowed reasons.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=21

Add support for immutable collections of Google Guava

Google Guava provides several immutable utility classes, for example ImmutableList.

If there is an assignment to a final field in a constructor like

this.foo = ImmutableList.of();

it is reported as

org.mutabilitydetector.unittesting.MutabilityAssertionError: 
  Expected: ... to be IMMUTABLE
       but: ... is actually NOT_IMMUTABLE
      Reasons:
          Field can have an abstract type (com.google.common.collect.ImmutableList) assigned to it. [Field: foo, Class: ...]
      Allowed reasons:
          None.

FindBugs plugin does not change analysis result when class is made immutable

Original author: [email protected] (April 19, 2012 18:49:56)

As reported by email (name withheld)

To reproduce

  1. create a project and write a simple class that is mutable.
  2. run FindBugs, the class is detected as mutable as expected.
  3. fix the class so that it now is immutable.
  4. optionally clear the Find Bugs Markers, Refresh, Clean...
  5. rerun FindBugs, the class is (wrongly) still detected as mutable

If you now restart Eclipse and run FindBugs again the fixed class
will correctly be detected as immutable.

I can also reproduce the bug when I do the test the other way round
(start with immutable class, run findBugs, make it mutable,
rerun findBugs -> class is not detected, restart Eclipse, class is detected).

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=26

Subclass will not be rendered mutable when superclass is definitely not immutable

Original author: [email protected] (December 23, 2009 00:38:41)

Given the following classes:

{{{
public class MutableSupertype {
public int mutableField;

public MutableSupertype(int num) {
    this.mutableField = num;
}

}

final class ImmutableSubtypeOfMutableSupertype extends MutableSupertype {
private final int immutableField = 2;
public ImmutableSubtypeOfMutableSupertype(int immutableField) {
super(immutableField);
}
}

}}}

The class ImmutableSubtypeOfMutableSupertype will be reported as definitely
immutable. This is incorrect because the mutability of MutableSupertype is
inherited, ie the value for mutableField can be changed in instances of
the subclass.

The mutability status of the superclass should be inherited.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=4

java.util.Optional is considered mutable

After looking at the test results once issue #56, I noticed this in one of the error messages from the test:

Field can have a mutable type (java.util.Optional) assigned to it. [Field: cause, Class: com.equalexperts.logging.LogicalLogRecord]

I think that instances of java.util.Optional should probably be considered immutable so long as the class they are referencing is immutable. It's not in my case, as java.lang.Throwable isn't really immutable, but I suspect that's not why the error was raised.

Thoughts?

Distinguish between Immutable and Effectively Immutable

Original author: [email protected] (July 09, 2011 17:40:14)

The following class is effectively immutable:

{{{
public final class EffectivelyImmutable {
private String field;
public EffectivelyImmutable(String field) {
this.field = field;
}

public String getField() {
    return this.field;
}

}
}}}

This means that to be used in multi threaded code, extra care has to be taken to publish the reference safely. This is due to the lack of 'final' on the field, which means that if unsafely published, clients could see the result of getField() change from null to a valid String reference. That extra care needs to be taken should be made obvious by distinguishing between Immutable and Effectively Immutable

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=16

Add hamcrest as a maven dependency instead of repackaging it

Original author: [email protected] (July 21, 2012 13:27:47)

Many projects are using hamcrest already, so the repackaged one found in the mutability detector artifact is an unnecessary overhead. Please do not repackage it, but instead simply add a runtime dependency to your POM. That way, maven will safely provide the needed classes under the hood, and keep the user free from duplicate binaries.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=29

Override MutabilityAssert.assertInstancesOf to take an Iterable of allowed reasons

Original author: [email protected] (October 26, 2012 12:34:07)

I tried to use JUnit's @theory tests to have mutability assertions for several classes. Each had various different allowed reasons (of type Matcher<MutableReasonDetail>). Each datapoint then consisted of the class to test, plus the allowed reason(s) for that class.

For reasons I can't remember, Matchers.allOf(firstReason, secondReason) doesn't work.

So then I tried to have variable number of allowed reasons for each class, and this doesn't work either, because of the signature(s) of assertInstancesOf:

assertInstancesOf(Matcher m1)
assertInstancesOf(Matcher m1, Matcher m2)
...
assertInstancesOf(Matcher m1, , Matcher mn, Matcher... mn+)

I would have needed to unpack an array/collection of allowed reasons to pick the correct signature. Meh.

This problem can be fixed by adding:
assertInstancesOf(Iterable<Matcher> matchers)

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=30

Catastrophic failures will not cause test to fail.

Original author: [email protected] (April 15, 2011 12:50:44)

What steps will reproduce the problem?

  1. Ensure an old version of asm (e.g. v1.4) on the classpath.
  2. Make a call to MutabilityAssert.isImmutable() with a mutable class (e.g. java.util.List)
  3. Run the unit test, and observe that it passes without problem.

What is the expected output? What do you see instead?
An exception to bubble up (NoSuchMethodError on an instance of an asm class) informing the user that the test could not complete normally, inducing failure of the test.

What version of the product are you using? On what operating system?
0.6-SNAPSHOT

This will occur for any type of runtime exception thrown during analysis of the class.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=11

Improve error message for Collections being wrapped without safe copy

Currently the error message for a collection field being wrapped without a safe copy is "Attempts to wrap mutable collection type without safely performing a copy first". It would be useful to provide a hint how a safe copy can be performed for the current use case. For instance for a List this can be achieved with:

Collections.unmodifiableList(new ArrayList(sourceList));

The goal of this issue is to improve the current error message with such hints how the copy can be done so that Mutability Detector does not report an error anymore.

Here a test which asserts the current error message:

    public final static class ClassWrappingCollectionWithoutCopy {
        private final Collection<String> collection;

        public ClassWrappingCollectionWithoutCopy(Collection<String> collection) {
            this.collection = Collections.unmodifiableCollection(collection);
        }
    }

    @Test
    public void isImmutableMutableTypeToField_ClassWrappingCollectionWithoutCopy() throws Exception {
        try {
            assertImmutable(ClassWrappingCollectionWithoutCopy.class);
            fail("Error should be thrown");
        } catch (MutabilityAssertionError e) {
            assertThat(e.getMessage(), is("\n"+
                    "Expected: org.mutabilitydetector.ErrorLocationTest$ClassWrappingCollectionWithoutCopy to be IMMUTABLE\n" +
                    "     but: org.mutabilitydetector.ErrorLocationTest$ClassWrappingCollectionWithoutCopy is actually NOT_IMMUTABLE\n" +
                    "    Reasons:\n" +
                    "        Attempts to wrap mutable collection type without safely performing a copy first. [Field: collection, Class: org.mutabilitydetector.ErrorLocationTest$ClassWrappingCollectionWithoutCopy]\n" +
                    "    Allowed reasons:\n" +
                    "        None."));
        }
    }

The packaged jar will be incompatible with the vast majority of project setups.

Original author: [email protected] (April 17, 2011 10:56:53)

Mutability Detector uses features of Hamcrest 1.2 which were not available in Hamcrest 1.1. If Hamcrest 1.1. is on the classpath before 1.2, there will be exceptions thrown within MutabilityAssert.assertX methods (along the lines of NoSuchMethodError for org.hamcrest.Matcher#describeMismatch).

This is compounded by the fact that the most widely used versions of JUnit either bundle Hamcrest 1.1 in the jar, or declare a dependency on that specific version*. Thus, if you have JUnit on the classpath for testing (that's the 'vast majority' part) it's likely that MutabilityAssert.assertX methods will throw an exception.

Suggested fix: as much as it hurts, downgrade the code using Hamcrest 1.2 features to get by on 1.1 features.

  • There are signature incompatibilities between hamcrest 1.1 and 1.2 and it's not a simple matter of JUnit upgrading.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=12

Correctly analyse the rule "don't allow subclassing"

Original author: [email protected] (November 15, 2011 22:14:36)

Currently, the analysis for this rule only checks whether the class has the final modifier or not. There is at least one other way to prevent subclassing, that is to only have private constructors. The analysis should check for this, passing the rule if at least one is true.

If leaving off the final modifier, the analysis for only private constructors should be fairly easy: visit every constructor and fail if any is not private.

The allowingSubclassing matcher should be updated to reflect this change.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=17

enhancement: Improve analysis for Optional collections

The mutability detector does a great job of detecting when collection parameters have been made safely immutable. It would be absolutely wonderful if this also worked for Optional collection parameters such as Optional<Set<String>>.

When the mutability detector encounters a field assignment for a collection such as this.s = Collections.unmodifiableSet(new HashSet<>(s));, it correctly allows the assignment. This is a bit problematic with Optional<Set<String>>, because we don't know if the collection is going to exist or not.

A simple and elegant guarantee that will work well with Optional collections is to map the resulting collection, if it exists: this.s = s.map(HashSet::new).map(Collections::unmodifiableSet);, which does the same thing, if the Optional isn't empty.

I've created a gist that illustrates the technique.

This might also work for fields of type Supplier<Set<T>>, which can have similar issues (and more, because there's no way of knowing if the supplier just generates a whole new collection each time it is called).

Currently, I have visually inspected that a class uses the technique correctly, and then added an allowed reason for immutability, but that's obviously error prone.

What do you think?

java.lang.String and java.lang.Integer are reported as not immutable.

Original author: [email protected] (December 21, 2009 00:39:30)

java.lang.String is not reported as immutable because it lazily initialises
a field, which is therefore not declared as final. This could be quite a
tricky thing to detect correctly. I believe an adequate way to detect this
pattern is:
when a field is not private
find where it can be reassigned
check it can only be assigned once
search for a conditional that will assess whether to assign
if condition is checking it against the default value for its type
declare it as immutable

This is probably the most complicated issue for detecting mutability, and
this particular logic is probably full of holes.

java.lang.Integer is not reported as immutable because it has a primitive
array for a field. Currently, for a class to be declared immutable one of
the conditions is that each field is an immutable type. I decided that
primitive arrays are inherently mutable, which causes the result on
Integer. The solution for this specific issue would be to scan the class
and check that the primitive array is not mutated outwith the constructor.
A more general technique would be scanning the class to check that the
field is not mutated - immutable or not. This is more complex than is
necessary, I feel.

There can never be a 1.0 release while these classifications remain.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=3

Cyclic references will cause a stack overflow

Original author: [email protected] (January 04, 2012 22:09:36)

Analysis still barfs on cyclic references. For example, analysing a set of classes like:

class TwoFields {
FieldA a;
FieldB b;
// constructor that assigns
}

class FieldA {
FieldB b;
// constructor that assigns
}

class FieldB {
FieldA a;
// constructor that assigns
}

Will cause a stack overflow.

When FieldA is being analysed it tries to find if 'b' is mutable, so it triggers an analysis of FieldB, which, when it comes to checking if 'a' is a mutable type, will trigger an analysis of FieldA.

As far as I can intuit, it is still possible to have immutable classes with this pattern (the instances in the cyclic references can't be the same, but the types can).

I am leaning towards being lazy about this scenario as it seems fairly unlikely. Declare a limitation of analysis, and show a nice error accurately describing the circular relationship.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=22

Non-static inner classes, do they pose an issue?

After fixing issue #33, a discussion about non-static inner classes lead to the below inquiry, @Grundlefleck recommended investigating further:

In terms of inner classes, static inner classes are no issue at all. They do not have a reference to the enclosing class so state changed does not affect the outer class. Non-static inner classes may be an issue, and worth investigating more, but I don't think it should hold up this issue, as I suspect the builder pattern would be more common for immutable classes. Worth a look though, if you're interested.

If the outcome of the investigation helps prove that the initial theory was correct about non-static classes being a problem, it will be considered an issue for further investigation and fixing.

Assertion mechanism should allow for dependency on other types being immutable.

Original author: [email protected] (November 06, 2010 14:24:57)

The 1.6 release of JodaTime (and the trunk version) contains classes with Javadoc comments such as:

"LocalDateTime is thread-safe and immutable, provided that the Chronology is as well."

When calling MutabilityAssert.assertImmutable(LocalDateTime.class) the test fails, with the message:

"Field [iChronology] can have an abstract type (org.joda.time.Chronology) assigned to it."

(Where iChronology is a field of LocalDateTime instances)

It should be possible, in a unit test, to specify this kind of relationship/dependency on a different class. The assertion should pass if (and only if) the only reason the class would be declared mutable is because of dependence on the immutability of the other class.

Eg:
assertImmutable(Class<?> expectedImmutable, Class<?>... asLongAsTheseAreAlsoImmutable)

[though this example is pretty ugly]

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=10

Cannot use an implementation of org.hamcrest.Matcher in unit tests

Original author: [email protected] (November 22, 2011 21:24:15)

A copy of hamcrest is bundled with the Mutability Detector jar. Like the other dependencies, this is repackaged into the org.mutabilitydetector namespace. Unfortunately, the types in the signature of MutabilityAssert.assertX have also been repackaged. This means that users have to implement org.mutabilitydetector...org.hamcrest.Matcher to supply their own.

I'm not sure if the org.hamcrest.Matcher class can just be excluded from the repackaging, since a default jar for JUnit includes the same type (but a different version). The solution might be to give up on using org.hamcrest.Matcher, and introduce a MutabilityDetector-specific matcher type. Not sure yet.

Original issue: http://code.google.com/p/mutability-detector/issues/detail?id=20

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.