/* * Copyright 2017 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.errorprone.bugpatterns.testdata; import com.google.errorprone.annotations.Immutable; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; /** Positive test cases for {@link ConstructorLeaksThis}. */ @Immutable public class ConstructorLeaksThisPositiveCases { // Named for com.google.testing.junit.junit4.rules.FixtureController, // which is generally initialized with a leaked 'this'. private static class FixtureController { FixtureController(@SuppressWarnings("unused") Object testObject) {} } // Method invocation in field initializer // BUG: Diagnostic contains: Constructors should not pass the 'this' reference final int hash = Objects.hash(this); // New call in field initializer // BUG: Diagnostic contains: Constructors should not pass the 'this' reference final FixtureController controller = new FixtureController(this); { // Method invocation in instance initializer // BUG: Diagnostic contains: Constructors should not pass the 'this' reference System.out.println(this); // New call in instance initializer // BUG: Diagnostic contains: Constructors should not pass the 'this' reference new FixtureController(this); } ConstructorLeaksThisPositiveCases() { // Method invocation in constructor // BUG: Diagnostic contains: Constructors should not pass the 'this' reference System.out.println(this); // New call in constructor // BUG: Diagnostic contains: Constructors should not pass the 'this' reference new AtomicReference<>(this); // Qualified reference inside a context where plain 'this' means something else new Thread() { @Override public void run() { // BUG: Diagnostic contains: Constructors should not pass the 'this' reference System.out.println(ConstructorLeaksThisPositiveCases.this); } }.start(); Runnable r = () -> System.out.println( // BUG: Diagnostic contains: Constructors should not pass the 'this' reference com.google.errorprone.bugpatterns.testdata.ConstructorLeaksThisPositiveCases.this); // BUG: Diagnostic contains: Constructors should not pass the 'this' reference r = () -> System.out.println(this); } public static class ThisInLambda { { // 'this' names not the lambda but the class under construction // BUG: Diagnostic contains: Constructors should not pass the 'this' reference new Thread(() -> System.out.println(this)).start(); } } /** Leak is signaled even if masked by cast expression */ static class CastRunnable implements Runnable { CastRunnable() { // BUG: Diagnostic contains: Constructors should not pass the 'this' reference new Thread((Runnable) this).start(); } @Override public void run() {} } }