mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ReadOnly -> Unmodifiable; introduced UnmodifiableView distinguish between unmodifiable and unmodifiable view
This commit is contained in:
+3
-3
@@ -1473,7 +1473,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
qualifierExpression.accept(this);
|
||||
}
|
||||
else if (myThisReadOnly) {
|
||||
addInstruction(new PushInstruction(myFactory.getFactValue(DfaFactType.MUTABLE, false), null));
|
||||
addInstruction(new PushInstruction(myFactory.getFactValue(DfaFactType.MUTABILITY, Mutability.UNMODIFIABLE), null));
|
||||
} else {
|
||||
pushUnknown();
|
||||
}
|
||||
@@ -1553,7 +1553,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
}
|
||||
}
|
||||
return CachedValueProvider.Result
|
||||
.create(Collections.<StandardMethodContract>emptyList(), method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
|
||||
.create(Collections.emptyList(), method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1768,7 +1768,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
startElement(expression);
|
||||
DfaValue value = myFactory.createTypeValue(expression.getType(), Nullness.NOT_NULL);
|
||||
if (myThisReadOnly) {
|
||||
value = myFactory.withFact(value, DfaFactType.MUTABLE, false);
|
||||
value = myFactory.withFact(value, DfaFactType.MUTABILITY, Mutability.UNMODIFIABLE);
|
||||
}
|
||||
addInstruction(new PushInstruction(value, expression));
|
||||
finishElement(expression);
|
||||
|
||||
@@ -74,17 +74,17 @@ public abstract class DfaFactType<T> extends Key<T> {
|
||||
}
|
||||
};
|
||||
|
||||
public static final DfaFactType<Boolean> MUTABLE = new DfaFactType<Boolean>("Mutable") {
|
||||
public static final DfaFactType<Mutability> MUTABILITY = new DfaFactType<Mutability>("Mutable") {
|
||||
@Override
|
||||
String toString(@NotNull Boolean fact) {
|
||||
return fact ? "Mutable" : "ReadOnly";
|
||||
boolean isUnknown(@NotNull Mutability fact) {
|
||||
return fact == Mutability.UNKNOWN;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
@Override
|
||||
Boolean calcFromVariable(@NotNull DfaVariableValue value) {
|
||||
Mutability calcFromVariable(@NotNull DfaVariableValue value) {
|
||||
PsiModifierListOwner variable = value.getPsiVariable();
|
||||
return MutationSignature.getMutabilityFact(variable);
|
||||
return Mutability.getMutability(variable);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -1222,7 +1222,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
|
||||
}
|
||||
for (DfaVariableValue value : vars) {
|
||||
if (value.isFlushableByCalls() && (value.getQualifier() == null ||
|
||||
!Boolean.FALSE.equals(getValueFact(value.getQualifier(), DfaFactType.MUTABLE)))) {
|
||||
getValueFact(value.getQualifier(), DfaFactType.MUTABILITY) != Mutability.UNMODIFIABLE)) {
|
||||
doFlush(value, shouldMarkUnknown(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public enum Mutability {
|
||||
UNKNOWN, MUTABLE, UNMODIFIABLE, UNMODIFIABLE_VIEW;
|
||||
|
||||
@NotNull
|
||||
static Mutability getMutability(PsiModifierListOwner owner) {
|
||||
if (owner instanceof PsiParameter && owner.getParent() instanceof PsiParameterList) {
|
||||
PsiParameterList list = (PsiParameterList)owner.getParent();
|
||||
PsiMethod method = ObjectUtils.tryCast(list.getParent(), PsiMethod.class);
|
||||
if (method != null) {
|
||||
int index = list.getParameterIndex((PsiParameter)owner);
|
||||
MutationSignature signature = MutationSignature.fromMethod(method);
|
||||
if (signature.mutatesArg(index)) {
|
||||
return MUTABLE;
|
||||
} else if (signature.preservesArg(index) &&
|
||||
PsiTreeUtil.findChildOfAnyType(method.getBody(), PsiLambdaExpression.class, PsiClass.class) == null) {
|
||||
// If method preserves argument, it still may return a lambda which captures an argument and changes it
|
||||
// TODO: more precise check (at least differentiate parameters which are captured by lambdas or not)
|
||||
return UNMODIFIABLE_VIEW;
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(owner, Collections.singleton("org.jetbrains.annotations.Unmodifiable"),
|
||||
AnnotationUtil.CHECK_HIERARCHY |
|
||||
AnnotationUtil.CHECK_EXTERNAL |
|
||||
AnnotationUtil.CHECK_INFERRED)) {
|
||||
return UNMODIFIABLE;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(owner, Collections.singleton("org.jetbrains.annotations.UnmodifiableView"),
|
||||
AnnotationUtil.CHECK_HIERARCHY |
|
||||
AnnotationUtil.CHECK_EXTERNAL |
|
||||
AnnotationUtil.CHECK_INFERRED)) {
|
||||
return UNMODIFIABLE_VIEW;
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
-28
@@ -3,13 +3,10 @@ package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
public class MutationSignature {
|
||||
private static final String ATTR_MUTATES = "mutates";
|
||||
@@ -121,29 +118,4 @@ public class MutationSignature {
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Boolean getMutabilityFact(PsiModifierListOwner owner) {
|
||||
if (owner instanceof PsiParameter && owner.getParent() instanceof PsiParameterList) {
|
||||
PsiParameterList list = (PsiParameterList)owner.getParent();
|
||||
PsiMethod method = ObjectUtils.tryCast(list.getParent(), PsiMethod.class);
|
||||
if (method != null) {
|
||||
int index = list.getParameterIndex((PsiParameter)owner);
|
||||
MutationSignature signature = fromMethod(method);
|
||||
if (signature.mutatesArg(index)) {
|
||||
return Boolean.TRUE;
|
||||
} else if (signature.preservesArg(index) &&
|
||||
PsiTreeUtil.findChildOfAnyType(method.getBody(), PsiLambdaExpression.class, PsiClass.class) == null) {
|
||||
// If method preserves argument, it still may return a lambda which captures an argument and changes it
|
||||
// TODO: more precise check (at least differentiate parameters which are captured by lambdas or not)
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return AnnotationUtil.isAnnotated(owner, Collections.singleton("org.jetbrains.annotations.ReadOnly"),
|
||||
AnnotationUtil.CHECK_HIERARCHY |
|
||||
AnnotationUtil.CHECK_EXTERNAL |
|
||||
AnnotationUtil.CHECK_INFERRED) ? Boolean.FALSE : null;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -368,10 +368,10 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
else if (requiredNullability == Nullness.UNKNOWN) {
|
||||
checkNotNullable(memState, arg, NullabilityProblemKind.passingNullableArgumentToNonAnnotatedParameter.problem(anchor));
|
||||
}
|
||||
if (sig.mutatesArg(paramIndex) && !memState.applyFact(arg, DfaFactType.MUTABLE, true)) {
|
||||
if (sig.mutatesArg(paramIndex) && !memState.applyFact(arg, DfaFactType.MUTABILITY, Mutability.MUTABLE)) {
|
||||
reportMutabilityViolation(false, anchor);
|
||||
if (arg instanceof DfaVariableValue) {
|
||||
memState.forceVariableFact((DfaVariableValue)arg, DfaFactType.MUTABLE, true);
|
||||
memState.forceVariableFact((DfaVariableValue)arg, DfaFactType.MUTABILITY, Mutability.MUTABLE);
|
||||
}
|
||||
}
|
||||
if (argValues != null && (paramIndex < argValues.length - 1 || !varargCall)) {
|
||||
@@ -388,10 +388,10 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
DfaMemoryState memState,
|
||||
MutationSignature sig) {
|
||||
DfaValue value = dereference(memState, memState.pop(), instruction.getQualifierNullabilityProblem());
|
||||
if (sig.mutatesThis() && !memState.applyFact(value, DfaFactType.MUTABLE, true)) {
|
||||
if (sig.mutatesThis() && !memState.applyFact(value, DfaFactType.MUTABILITY, Mutability.MUTABLE)) {
|
||||
reportMutabilityViolation(true, instruction.getContext());
|
||||
if (value instanceof DfaVariableValue) {
|
||||
memState.forceVariableFact((DfaVariableValue)value, DfaFactType.MUTABLE, true);
|
||||
memState.forceVariableFact((DfaVariableValue)value, DfaFactType.MUTABILITY, Mutability.MUTABLE);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
@@ -511,13 +511,13 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
if (type != null && !(type instanceof PsiPrimitiveType)) {
|
||||
Nullness nullability = instruction.getReturnNullability();
|
||||
PsiMethod targetMethod = instruction.getTargetMethod();
|
||||
Boolean mutable = null;
|
||||
Mutability mutable = Mutability.UNKNOWN;
|
||||
if (targetMethod != null) {
|
||||
mutable = MutationSignature.getMutabilityFact(targetMethod);
|
||||
mutable = Mutability.getMutability(targetMethod);
|
||||
PsiMethod realMethod = findSpecificMethod(targetMethod, state, qualifierValue);
|
||||
if (realMethod != targetMethod) {
|
||||
nullability = DfaPsiUtil.getElementNullability(type, realMethod);
|
||||
mutable = MutationSignature.getMutabilityFact(realMethod);
|
||||
mutable = Mutability.getMutability(realMethod);
|
||||
PsiType returnType = realMethod.getReturnType();
|
||||
if (returnType != null && TypeConversionUtil.erasure(type).isAssignableFrom(returnType)) {
|
||||
// possibly covariant return type
|
||||
@@ -529,7 +529,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
}
|
||||
}
|
||||
DfaValue value = factory.createTypeValue(type, nullability);
|
||||
return factory.withFact(value, DfaFactType.MUTABLE, mutable);
|
||||
return factory.withFact(value, DfaFactType.MUTABILITY, mutable);
|
||||
}
|
||||
LongRangeSet range = LongRangeSet.fromType(type);
|
||||
if (range != null) {
|
||||
|
||||
+2
-1
@@ -99,7 +99,8 @@ public class CollectionFactoryInliner implements CallInliner {
|
||||
builder.pop();
|
||||
}
|
||||
DfaValueFactory factory = builder.getFactory();
|
||||
DfaValue result = factory.withFact(factory.createTypeValue(call.getType(), Nullness.NOT_NULL), DfaFactType.MUTABLE, false);
|
||||
DfaValue result =
|
||||
factory.withFact(factory.createTypeValue(call.getType(), Nullness.NOT_NULL), DfaFactType.MUTABILITY, Mutability.UNMODIFIABLE);
|
||||
if (factoryInfo.mySize == -1) {
|
||||
builder.push(result);
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.ReadOnly;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -7,7 +7,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MutabilityBasics {
|
||||
@ReadOnly
|
||||
@Unmodifiable
|
||||
static <T> List<T> emptyList() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class MutabilityBasics {
|
||||
}
|
||||
}
|
||||
|
||||
@ReadOnly
|
||||
@Unmodifiable
|
||||
static Point getZero() {
|
||||
return new Point() {
|
||||
@Override
|
||||
@@ -59,12 +59,12 @@ public class MutabilityBasics {
|
||||
}
|
||||
|
||||
// Differs from getZero as getZero() is considered as getter with predefined value
|
||||
@ReadOnly
|
||||
@Unmodifiable
|
||||
static Point zero() {
|
||||
return getZero();
|
||||
}
|
||||
|
||||
@ReadOnly List<String> list = Arrays.asList("foo", "bar", "baz");
|
||||
@Unmodifiable List<String> list = Arrays.asList("foo", "bar", "baz");
|
||||
|
||||
void test() {
|
||||
List<String> collection = emptyList();
|
||||
|
||||
@@ -59,4 +59,18 @@ public class MutabilityJdk {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void testNoFlush() {
|
||||
List<String> list1 = Collections.emptyList();
|
||||
List<String> list2 = new ArrayList<>();
|
||||
List<String> list3 = Collections.unmodifiableList(list2);
|
||||
if(<warning descr="Condition 'list1.isEmpty()' is always 'true'">list1.isEmpty()</warning>) System.out.println("ok");
|
||||
if(!list3.isEmpty()) return;
|
||||
if(<warning descr="Condition '!list3.isEmpty()' is always 'false'">!<warning descr="Condition 'list3.isEmpty()' is always 'true'">list3.isEmpty()</warning></warning>) return;
|
||||
list2.add("foo");
|
||||
// list1 size is not flushed (UNMODIFIABLE)
|
||||
if(<warning descr="Condition 'list1.isEmpty()' is always 'true'">list1.isEmpty()</warning>) System.out.println("ok");
|
||||
// list3 size is flushed (UNMODIFIABLE_VIEW)
|
||||
if(!list3.isEmpty()) return;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -209,7 +209,7 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
|
||||
public void testCastInstanceOf() { doTest(); }
|
||||
|
||||
public void testMutabilityBasics() {
|
||||
myFixture.addClass("package org.jetbrains.annotations;public @interface ReadOnly {}");
|
||||
myFixture.addClass("package org.jetbrains.annotations;public @interface Unmodifiable {}");
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
@@ -1126,7 +1126,7 @@
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.UnmodifiableView" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
@@ -1160,22 +1160,22 @@
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.List<T> emptyList()">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.Unmodifiable" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.List<T> nCopies(int, T)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.Unmodifiable" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.List<T> singletonList(T)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.Unmodifiable" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.List<T> synchronizedList(java.util.List<T>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.List<T> unmodifiableList(java.util.List<? extends T>)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.UnmodifiableView" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.List<T> unmodifiableList(java.util.List<? extends T>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
@@ -1194,18 +1194,18 @@
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Map<K,V> emptyMap()">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.Unmodifiable" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Map<K,V> singletonMap(K, V)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.Unmodifiable" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Map<K,V> synchronizedMap(java.util.Map<K,V>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Map<K,V> unmodifiableMap(java.util.Map<? extends K,? extends V>)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.UnmodifiableView" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Map<K,V> unmodifiableMap(java.util.Map<? extends K,? extends V>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
@@ -1235,18 +1235,18 @@
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Set<T> emptySet()">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.Unmodifiable" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Set<T> singleton(T)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.Unmodifiable" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Set<T> synchronizedSet(java.util.Set<T>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.UnmodifiableView" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
@@ -1265,7 +1265,7 @@
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.SortedMap<K,V> unmodifiableSortedMap(java.util.SortedMap<K,? extends V>)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.UnmodifiableView" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.SortedMap<K,V> unmodifiableSortedMap(java.util.SortedMap<K,? extends V>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
@@ -1278,14 +1278,14 @@
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.SortedSet<E> emptySortedSet()">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.Unmodifiable" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
<annotation name="org.jetbrains.annotations.ReadOnly" />
|
||||
<annotation name="org.jetbrains.annotations.UnmodifiableView" />
|
||||
</item>
|
||||
<item name="java.util.Collections java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2000-2017 JetBrains s.r.o.
|
||||
//
|
||||
// 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 org.jetbrains.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* An annotation which depicts that method returns a read-only value or a variable
|
||||
* contains a read-only value. Read-only value means that calling methods which may
|
||||
* mutate this value (alter visible behavior) either don't have any effect or throw
|
||||
* an exception. This does not mean that value cannot be altered at all. For example,
|
||||
* a value could be a read-only wrapper over a mutable value.
|
||||
* <p>
|
||||
* This annotation is experimental and may be changed/removed in future
|
||||
* without additional notice!
|
||||
* </p>
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
|
||||
@ApiStatus.Experimental
|
||||
public @interface ReadOnly {
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
package org.jetbrains.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* An annotation which depicts that method returns an unmodifiable value or a variable
|
||||
* contains an unmodifiable value. Unmodifiable value means that calling methods which may
|
||||
* mutate this value (alter visible behavior) either don't have any effect or throw
|
||||
* an exception.
|
||||
* <p>
|
||||
* This annotation is experimental and may be changed/removed in future
|
||||
* without additional notice!
|
||||
* </p>
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
|
||||
@ApiStatus.Experimental
|
||||
public @interface Unmodifiable {
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
package org.jetbrains.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* An annotation which depicts that method returns an unmodifiable value or a variable
|
||||
* contains an unmodifiable view. Unmodifiable view means that calling methods which may
|
||||
* mutate this value (alter visible behavior) either don't have any effect or throw
|
||||
* an exception. However this value could be modified by third-party, thus methods reading
|
||||
* the object content might return different result.
|
||||
* <p>
|
||||
* This annotation is experimental and may be changed/removed in future
|
||||
* without additional notice!
|
||||
* </p>
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
|
||||
@ApiStatus.Experimental
|
||||
public @interface UnmodifiableView {
|
||||
}
|
||||
Reference in New Issue
Block a user