Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
irengrig
2011-02-25 13:20:05 +03:00
64 changed files with 966 additions and 638 deletions
@@ -246,8 +246,8 @@ public class ExceptionUtil {
unhandledExceptions = unhandled;
}
if (element instanceof PsiResource) {
final List<PsiClassType> unhandled = getUnhandledCloserExceptions((PsiResource)element, topElement);
if (element instanceof PsiResourceVariable) {
final List<PsiClassType> unhandled = getUnhandledCloserExceptions((PsiResourceVariable)element, topElement);
if (unhandledExceptions == null) {
unhandledExceptions = unhandled;
}
@@ -331,7 +331,7 @@ public class ExceptionUtil {
}
@NotNull
public static List<PsiClassType> getUnhandledCloserExceptions(final PsiResource resource, final PsiElement topElement) {
public static List<PsiClassType> getUnhandledCloserExceptions(final PsiResourceVariable resource, final PsiElement topElement) {
final PsiType resourceType = resource.getType();
if (resourceType instanceof PsiClassType) {
final PsiClass resourceClass = ((PsiClassType)resourceType).resolve();
@@ -675,8 +675,8 @@ public class HighlightControlFlowUtil {
@Nullable
public static PsiClass getInnerClassVariableReferencedFrom(PsiVariable variable, PsiElement context) {
PsiElement[] scope;
if (variable instanceof PsiScopedLocalVariable) {
scope = ((PsiScopedLocalVariable)variable).getDeclarationScope();
if (variable instanceof PsiResourceVariable) {
scope = ((PsiResourceVariable)variable).getDeclarationScope();
}
else if (variable instanceof PsiLocalVariable) {
scope = new PsiElement[]{variable.getParent().getParent()}; // code block or for statement
@@ -435,7 +435,7 @@ public class HighlightUtil {
@Nullable
static HighlightInfo checkVariableInitializerType(PsiVariable variable) {
PsiExpression initializer = variable.getInitializer();
// array initalizer checked in checkArrayInitializerApplicable
// array initializer checked in checkArrayInitializerApplicable
if (initializer == null || initializer instanceof PsiArrayInitializerExpression) return null;
PsiType lType = variable.getType();
PsiType rType = initializer.getType();
@@ -608,7 +608,9 @@ public class HighlightUtil {
if (isIncorrect) {
String description = JavaErrorMessages.message("variable.already.defined", name);
HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, identifier, description);
QuickFixAction.registerQuickFixAction(highlightInfo, new ReuseVariableDeclarationFix(variable, identifier));
if (!(variable instanceof PsiResourceVariable)) {
QuickFixAction.registerQuickFixAction(highlightInfo, new ReuseVariableDeclarationFix(variable, identifier));
}
return highlightInfo;
}
return null;
@@ -655,7 +657,7 @@ public class HighlightUtil {
}
@Nullable
public static HighlightInfo checkUnhandledCloserExceptions(final PsiResource resource) {
public static HighlightInfo checkUnhandledCloserExceptions(final PsiResourceVariable resource) {
final List<PsiClassType> unhandled = ExceptionUtil.getUnhandledCloserExceptions(resource, null);
if (unhandled.isEmpty()) return null;
@@ -1148,7 +1150,7 @@ public class HighlightUtil {
}
@Nullable
public static HighlightInfo checkTryResourceIsAutoCloseable(@NotNull final PsiResource resource) {
public static HighlightInfo checkTryResourceIsAutoCloseable(@NotNull final PsiResourceVariable resource) {
final PsiType type = resource.getType();
if (type == null) return null;
@@ -906,11 +906,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
@Override
public void visitResource(final PsiResource resource) {
myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource));
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource));
}
public void visitResourceVariable(final PsiResourceVariable resourceVariable) {
visitVariable(resourceVariable);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resourceVariable));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resourceVariable));
}
@Override public void visitTypeElement(PsiTypeElement type) {
@@ -57,7 +57,6 @@ public class ReuseVariableDeclarationFix implements IntentionAction {
return myVariable != null &&
myVariable.isValid() &&
myVariable instanceof PsiLocalVariable &&
!(myVariable.getParent() instanceof PsiResource && myVariable.getInitializer() == null) &&
previousVariable != null &&
Comparing.equal(previousVariable.getType(), myVariable.getType()) &&
myIdentifier != null &&
@@ -78,17 +77,9 @@ public class ReuseVariableDeclarationFix implements IntentionAction {
}
PsiUtil.setModifierProperty(refVariable, PsiModifier.FINAL, false);
final PsiElementFactory factory = JavaPsiFacade.getInstance(myVariable.getProject()).getElementFactory();
final PsiElement replacement;
final PsiElement parent = myVariable.getParent();
if (parent instanceof PsiResource) {
replacement = factory.createResourceFromText(myVariable.getName() + " = " + initializer.getText(), null);
}
else {
replacement = factory.createStatementFromText(myVariable.getName() + " = " + initializer.getText() + ";", null);
}
parent.replace(replacement);
final PsiElement statement = factory.createStatementFromText(myVariable.getName() + " = " + initializer.getText() + ";", null);
myVariable.getParent().replace(statement);
}
@Nullable
@@ -97,7 +97,7 @@ public class DefUseInspection extends BaseLocalInspectionTool {
PsiElement context = info.getContext();
PsiVariable psiVariable = info.getVariable();
if (context instanceof PsiDeclarationStatement || context instanceof PsiResource) {
if (context instanceof PsiDeclarationStatement || context instanceof PsiResourceVariable) {
if (!info.isRead()) {
if (!isOnTheFly) {
holder.registerProblem(psiVariable.getNameIdentifier(),
@@ -36,7 +36,7 @@ import static com.intellij.lang.java.parser.JavaParserUtil.exprType;
public class DeclarationParser {
public enum Context {
FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE, RESOURCE_LIST
FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE
}
private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD);
@@ -223,7 +223,7 @@ public class DeclarationParser {
if (tokenType == null) return null;
if (tokenType == JavaTokenType.LBRACE) {
if (context == Context.FILE || context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) return null;
if (context == Context.FILE || context == Context.CODE_BLOCK) return null;
}
else if (tokenType == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) {
if (context == Context.FILE) return null;
@@ -235,7 +235,7 @@ public class DeclarationParser {
else if (!ElementType.MODIFIER_BIT_SET.contains(tokenType) &&
!ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType) &&
tokenType != JavaTokenType.AT &&
(context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST || tokenType != JavaTokenType.LT)) {
(context == Context.CODE_BLOCK || tokenType != JavaTokenType.LT)) {
return null;
}
@@ -279,7 +279,7 @@ public class DeclarationParser {
final PsiBuilder.Marker idPos = builder.mark();
type = parseTypeNotNull(builder);
if (builder.getTokenType() == JavaTokenType.LPARENTH) { // constructor
if (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) {
if (context == Context.CODE_BLOCK) {
declaration.rollbackTo();
return null;
}
@@ -302,10 +302,6 @@ public class DeclarationParser {
declaration.drop();
return modList;
}
else if (context == Context.RESOURCE_LIST) {
declaration.rollbackTo();
return null;
}
final PsiBuilder.Marker codeBlock = StatementParser.parseCodeBlock(builder);
assert codeBlock != null : builder.getOriginalText();
@@ -331,7 +327,7 @@ public class DeclarationParser {
}
if (!expect(builder, JavaTokenType.IDENTIFIER)) {
if ((context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) && modListInfo.second) {
if ((context == Context.CODE_BLOCK) && modListInfo.second) {
declaration.rollbackTo();
return null;
}
@@ -473,11 +469,11 @@ public class DeclarationParser {
PsiBuilder.Marker invalidElements = null;
String errorMessage = null;
boolean delimiterExpected = false;
int elementCount = 0;
boolean noElements = true;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null || tokenType == JavaTokenType.RPARENTH || tokenType == JavaTokenType.LBRACE) {
boolean noLastElement = !delimiterExpected && elementCount > 0;
final boolean noLastElement = !delimiterExpected && (!noElements && !resources || noElements && resources);
if (noLastElement) {
error(builder, JavaErrorMessages.message("expected.identifier.or.type"));
}
@@ -486,13 +482,10 @@ public class DeclarationParser {
invalidElements.error(errorMessage);
invalidElements = null;
}
else if (resources && elementCount == 0) {
error(builder, JavaErrorMessages.message("expected.resource"));
}
builder.advanceLexer();
}
else {
if (!noLastElement) {
if (!noLastElement || resources) {
if (invalidElements != null) {
invalidElements.error(errorMessage);
}
@@ -522,7 +515,7 @@ public class DeclarationParser {
invalidElements.errorBefore(errorMessage, listElement);
invalidElements = null;
}
elementCount++;
noElements= false;
continue;
}
}
@@ -531,6 +524,9 @@ public class DeclarationParser {
if (builder.getTokenType() == delimiter) {
error(builder, noElementMsg);
builder.advanceLexer();
if (noElements && resources) {
noElements = false;
}
continue;
}
else {
@@ -556,6 +552,19 @@ public class DeclarationParser {
@Nullable
public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunctiveType) {
return parseListElement(builder, ellipsis, disjunctiveType, false);
}
@Nullable
public static PsiBuilder.Marker parseResource(final PsiBuilder builder) {
return parseListElement(builder, false, false, true);
}
@Nullable
private static PsiBuilder.Marker parseListElement(final PsiBuilder builder,
final boolean ellipsis,
final boolean disjunctiveType,
final boolean resource) {
final PsiBuilder.Marker param = builder.mark();
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
@@ -577,34 +586,26 @@ public class DeclarationParser {
}
if (expect(builder, JavaTokenType.IDENTIFIER)) {
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen"));
done(param, JavaElementType.PARAMETER);
return param;
if (!resource) {
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen"));
done(param, JavaElementType.PARAMETER);
return param;
}
}
else {
error(builder, JavaErrorMessages.message("expected.identifier"));
param.drop();
return modListInfo.first;
}
}
@Nullable
public static PsiBuilder.Marker parseResource(final PsiBuilder builder) {
PsiBuilder.Marker element = parse(builder, Context.RESOURCE_LIST);
if (exprType(element) == JavaElementType.MODIFIER_LIST) {
return element;
}
else if (element == null) {
element = ExpressionParser.parse(builder);
if (expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq"))) {
if (ExpressionParser.parse(builder) == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
}
}
if (element != null) {
final PsiBuilder.Marker resource = element.precede();
done(resource, JavaElementType.RESOURCE);
return resource;
}
return null;
done(param, JavaElementType.RESOURCE_VARIABLE);
return param;
}
@Nullable
@@ -614,7 +615,7 @@ public class DeclarationParser {
if (context == Context.CLASS || context == Context.ANNOTATION_INTERFACE) {
varType = JavaElementType.FIELD;
}
else if (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) {
else if (context == Context.CODE_BLOCK) {
varType = JavaElementType.LOCAL_VARIABLE;
}
else {
@@ -645,11 +646,6 @@ public class DeclarationParser {
unclosed = true;
break;
}
if (context == Context.RESOURCE_LIST) break;
}
else if (context == Context.RESOURCE_LIST) {
error(builder, JavaErrorMessages.message("expected.eq"));
break;
}
if (builder.getTokenType() != JavaTokenType.COMMA) break;
@@ -668,28 +664,26 @@ public class DeclarationParser {
builder.advanceLexer();
}
if (context != Context.RESOURCE_LIST) {
if (builder.getTokenType() == JavaTokenType.SEMICOLON && eatSemicolon) {
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.SEMICOLON && eatSemicolon) {
builder.advanceLexer();
}
else {
// special treatment (see DeclarationParserTest.testMultiLineUnclosed())
if (!builder.eof() && shouldRollback) {
final CharSequence text = builder.getOriginalText();
final int spaceEnd = builder.getCurrentOffset();
final int spaceStart = CharArrayUtil.shiftBackward(text, spaceEnd-1, WHITESPACES);
final int lineStart = CharArrayUtil.shiftBackwardUntil(text, spaceEnd, LINE_ENDS);
if (declarationStart < lineStart && lineStart < spaceStart) {
final int newBufferEnd = CharArrayUtil.shiftForward(text, lineStart, WHITESPACES);
declaration.rollbackTo();
return parse(stoppingBuilder(builder, newBufferEnd), context);
}
}
else {
// special treatment (see DeclarationParserTest.testMultiLineUnclosed())
if (!builder.eof() && shouldRollback) {
final CharSequence text = builder.getOriginalText();
final int spaceEnd = builder.getCurrentOffset();
final int spaceStart = CharArrayUtil.shiftBackward(text, spaceEnd-1, WHITESPACES);
final int lineStart = CharArrayUtil.shiftBackwardUntil(text, spaceEnd, LINE_ENDS);
if (declarationStart < lineStart && lineStart < spaceStart) {
final int newBufferEnd = CharArrayUtil.shiftForward(text, lineStart, WHITESPACES);
declaration.rollbackTo();
return parse(stoppingBuilder(builder, newBufferEnd), context);
}
}
if (!unclosed) {
error(builder, JavaErrorMessages.message("expected.semicolon"));
}
if (!unclosed) {
error(builder, JavaErrorMessages.message("expected.semicolon"));
}
}
@@ -1166,30 +1166,15 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
public void visitResourceList(final PsiResourceList resourceList) {
startElement(resourceList);
final List<PsiResource> resources = resourceList.getResources();
for (PsiResource resource : resources) {
final List<PsiResourceVariable> resources = resourceList.getResourceVariables();
for (PsiResourceVariable resource : resources) {
ProgressManager.checkCanceled();
resource.accept(this);
processVariable(resource);
}
finishElement(resourceList);
}
@Override
public void visitResource(final PsiResource resource) {
startElement(resource);
final PsiElement resourceElement = resource.getResourceElement();
if (resourceElement instanceof PsiLocalVariable) {
processVariable((PsiLocalVariable)resourceElement);
}
else if (resourceElement instanceof PsiExpression) {
resourceElement.accept(this);
}
finishElement(resource);
}
@Override
public void visitWhileStatement(PsiWhileStatement statement) {
startElement(statement);
@@ -230,11 +230,10 @@ public class DefUseUtil {
if (!defsArmed[i]) {
PsiElement context = PsiTreeUtil.getNonStrictParentOfType(flow.getElement(i),
PsiStatement.class, PsiAssignmentExpression.class,
PsiPostfixExpression.class, PsiPrefixExpression.class,
PsiResource.class);
PsiPostfixExpression.class, PsiPrefixExpression.class);
PsiVariable psiVariable = writeInstruction.variable;
if (context != null && !(context instanceof PsiTryStatement)) {
if (isDeclaration(context) && psiVariable.getInitializer() == null) {
if (context instanceof PsiDeclarationStatement && psiVariable.getInitializer() == null) {
if (!assignedVariables.contains(psiVariable)) {
unusedDefs.add(new Info(psiVariable, context, false));
}
@@ -250,11 +249,6 @@ public class DefUseUtil {
return unusedDefs;
}
private static boolean isDeclaration(final PsiElement context) {
return context instanceof PsiDeclarationStatement ||
context instanceof PsiResource && ((PsiResource)context).getResourceElement() instanceof PsiLocalVariable;
}
@NotNull
public static PsiElement[] getDefs(PsiCodeBlock body, final PsiVariable def, PsiElement ref) {
try {
@@ -198,12 +198,9 @@ public class PsiImplUtil {
@NotNull final PsiScopeProcessor processor,
@NotNull final ResolveState state,
final PsiElement lastParent) {
final List<PsiResource> resources = resourceList.getResources();
for (PsiResource resource : resources) {
final PsiElement resourceElement = resource.getResourceElement();
if (resourceElement instanceof PsiLocalVariable &&
!resourceElement.equals(lastParent) &&
!processor.execute(resourceElement, state)) return false;
final List<PsiResourceVariable> resources = resourceList.getResourceVariables();
for (PsiResourceVariable resource : resources) {
if (!resource.equals(lastParent) && !processor.execute(resource, state)) return false;
}
return true;
@@ -259,13 +259,13 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
@NotNull
@Override
public PsiResource createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException {
public PsiResourceVariable createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException {
final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, RESOURCE, false), context);
final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode());
if (!(element instanceof PsiResource)) {
if (!(element instanceof PsiResourceVariable)) {
throw new IncorrectOperationException("Incorrect resource \"" + text + "\".");
}
return (PsiResource)element;
return (PsiResourceVariable)element;
}
@NotNull
@@ -78,12 +78,6 @@ public class JavaModifierListElementType extends JavaStubElementType<PsiModifier
return node.getTreeParent().getElementType() != JavaElementType.LOCAL_VARIABLE;
}
@Override
public boolean shouldCreateStub(final LighterAST tree, final LighterASTNode node, final StubElement parentStub) {
final LighterASTNode parent = tree.getParent(node);
return parent != null && parent.getTokenType() != JavaElementType.LOCAL_VARIABLE;
}
public PsiModifierListStub deserialize(final StubInputStream dataStream, final StubElement parentStub) throws IOException {
return new PsiModifierListStubImpl(parentStub, dataStream.readVarInt());
}
@@ -49,7 +49,7 @@ public class JavaLightStubBuilder extends LightStubBuilder {
@Override
public boolean skipChildProcessingWhenBuildingStubs(final IElementType nodeType, final IElementType childType) {
return childType == JavaElementType.PARAMETER_LIST && nodeType != JavaElementType.METHOD && nodeType != JavaElementType.ANNOTATION_METHOD ||
childType == JavaElementType.PARAMETER && nodeType != JavaElementType.PARAMETER_LIST;
return childType == JavaElementType.PARAMETER && nodeType != JavaElementType.PARAMETER_LIST ||
childType == JavaElementType.MODIFIER_LIST && (nodeType == JavaElementType.LOCAL_VARIABLE || nodeType == JavaElementType.RESOURCE_VARIABLE);
}
}
@@ -177,9 +177,8 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
else if (parent instanceof PsiParameter) {
if (type == JavaTokenType.FINAL_KEYWORD && ((PsiParameter)parent).getType() instanceof PsiDisjunctionType) return true;
}
else if (parent instanceof PsiLocalVariable) {
PsiElement grandParent = parent.getParent();
if (type == JavaTokenType.FINAL_KEYWORD && grandParent instanceof PsiResource) return true;
else if (parent instanceof PsiResourceVariable) {
if (type == JavaTokenType.FINAL_KEYWORD) return true;
}
if (type == null) { // package local
@@ -128,7 +128,7 @@ public interface JavaElementType {
IElementType SYNCHRONIZED_STATEMENT = new JavaCompositeElementType("SYNCHRONIZED_STATEMENT", PsiSynchronizedStatementImpl.class);
IElementType TRY_STATEMENT = new JavaCompositeElementType("TRY_STATEMENT", PsiTryStatementImpl.class);
IElementType RESOURCE_LIST = new JavaCompositeElementType("RESOURCE_LIST", PsiResourceListImpl.class);
IElementType RESOURCE = new JavaCompositeElementType("RESOURCE", PsiResourceImpl.class);
IElementType RESOURCE_VARIABLE = new JavaCompositeElementType("RESOURCE_VARIABLE", PsiResourceVariableImpl.class);
IElementType CATCH_SECTION = new JavaCompositeElementType("CATCH_SECTION", PsiCatchSectionImpl.class);
IElementType LABELED_STATEMENT = new JavaCompositeElementType("LABELED_STATEMENT", PsiLabeledStatementImpl.class);
IElementType ASSERT_STATEMENT = new JavaCompositeElementType("ASSERT_STATEMENT", PsiAssertStatementImpl.class);
@@ -49,13 +49,17 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.Set;
public class PsiLocalVariableImpl extends CompositePsiElement implements PsiScopedLocalVariable, PsiVariableEx, Constants {
public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLocalVariable, PsiVariableEx, Constants {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiLocalVariableImpl");
private volatile String myCachedName = null;
public PsiLocalVariableImpl() {
super(LOCAL_VARIABLE);
this(LOCAL_VARIABLE);
}
protected PsiLocalVariableImpl(final IElementType type) {
super(type);
}
public void clearCaches() {
@@ -279,21 +283,6 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiScop
return "PsiLocalVariable:" + getName();
}
@NotNull
public PsiElement[] getDeclarationScope() {
final PsiElement parentElement = getParent();
if (parentElement instanceof PsiDeclarationStatement) {
return new PsiElement[]{parentElement.getParent()};
}
else if (parentElement instanceof PsiResource) {
final PsiResourceList resourceList = (PsiResourceList)parentElement.getParent();
final PsiTryStatement tryStatement = (PsiTryStatement)resourceList.getParent();
final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
return tryBlock != null ? new PsiElement[]{resourceList, tryBlock} : new PsiElement[]{resourceList};
}
return new PsiElement[]{parentElement.getParent()};
}
@NotNull
public SearchScope getUseScope() {
if (JspPsiUtil.isInJspFile(this)) {
@@ -321,8 +310,8 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiScop
}
final PsiElement parentElement = getParent();
if (parentElement instanceof PsiDeclarationStatement || parentElement instanceof PsiResource) {
return new LocalSearchScope(getDeclarationScope());
if (parentElement instanceof PsiDeclarationStatement) {
return new LocalSearchScope(parentElement.getParent());
}
else {
return getManager().getFileManager().getUseScope(this);
@@ -1,74 +0,0 @@
/*
* Copyright 2000-2011 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 com.intellij.psi.impl.source.tree.java;
import com.intellij.openapi.diagnostic.LogUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.CompositePsiElement;
import com.intellij.psi.impl.source.tree.JavaElementType;
import org.jetbrains.annotations.NotNull;
public class PsiResourceImpl extends CompositePsiElement implements PsiResource {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiResourceImpl");
public PsiResourceImpl() {
super(JavaElementType.RESOURCE);
}
@NotNull
@Override
public PsiElement getResourceElement() {
final PsiElement element = getFirstChild();
assert element != null : this;
return element;
}
@Override
public PsiType getType() {
final PsiElement element = getResourceElement();
if (element instanceof PsiLocalVariable) {
return ((PsiLocalVariable)element).getType();
}
else if (element instanceof PsiExpression) {
return ((PsiExpression)element).getType();
}
LOG.error("Unexpected resource type: " + LogUtil.objectAndClass(element));
return null;
}
@Override
public void accept(@NotNull final PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitResource(this);
}
else {
visitor.visitElement(this);
}
}
public String getName() {
final PsiElement element = getFirstChild();
if (element instanceof PsiLocalVariable) return ((PsiLocalVariable)element).getName();
if (element instanceof PsiAssignmentExpression) return ((PsiAssignmentExpression)element).getLExpression().toString();
return "";
}
@Override
public String toString() {
return "PsiResource:" + getName();
}
}
@@ -32,8 +32,8 @@ public class PsiResourceListImpl extends CompositePsiElement implements PsiResou
@NotNull
@Override
public List<PsiResource> getResources() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, PsiResource.class);
public List<PsiResourceVariable> getResourceVariables() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, PsiResourceVariable.class);
}
@Override
@@ -0,0 +1,70 @@
/*
* Copyright 2000-2011 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 com.intellij.psi.impl.source.tree.java;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
public class PsiResourceVariableImpl extends PsiLocalVariableImpl implements PsiResourceVariable {
public PsiResourceVariableImpl() {
super(JavaElementType.RESOURCE_VARIABLE);
}
@NotNull
@Override
public PsiElement[] getDeclarationScope() {
final PsiResourceList resourceList = (PsiResourceList)getParent();
final PsiTryStatement tryStatement = (PsiTryStatement)resourceList.getParent();
final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
return tryBlock != null ? new PsiElement[]{resourceList, tryBlock} : new PsiElement[]{resourceList};
}
@NotNull
@Override
public PsiTypeElement getTypeElement() {
return PsiTreeUtil.getRequiredChildOfType(this, PsiTypeElement.class);
}
@Override
public PsiModifierList getModifierList() {
return PsiTreeUtil.getChildOfType(this, PsiModifierList.class);
}
@Override
public void accept(@NotNull final PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitResourceVariable(this);
}
else {
visitor.visitElement(this);
}
}
@NotNull
@Override
public SearchScope getUseScope() {
return new LocalSearchScope(getDeclarationScope());
}
@Override
public String toString() {
return "PsiResourceVariable:" + getName();
}
}
@@ -15,9 +15,11 @@
*/
package com.intellij.unscramble;
import com.intellij.Patches;
import com.intellij.openapi.application.ApplicationAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.util.Alarm;
import java.util.regex.Pattern;
@@ -29,16 +31,29 @@ public class UnscrambleListener extends ApplicationAdapter {
private String stacktrace = null;
@Override
public void applicationActivated(IdeFrame ideFrame) {
final String clipboard = AnalyzeStacktraceUtil.getTextInClipboard();
if (clipboard != null && clipboard.length() < MAX_STACKTRACE_SIZE && !clipboard.equals(stacktrace)) {
stacktrace = clipboard;
final Project project = ideFrame.getProject();
if (project != null && isStacktrace(stacktrace)) {
final UnscrambleDialog dialog = new UnscrambleDialog(project);
dialog.createNormalizeTextAction().actionPerformed(null);
dialog.doOKAction();
public void applicationActivated(final IdeFrame ideFrame) {
final Runnable processClipboard = new Runnable() {
@Override
public void run() {
final String clipboard = AnalyzeStacktraceUtil.getTextInClipboard();
if (clipboard != null && clipboard.length() < MAX_STACKTRACE_SIZE && !clipboard.equals(stacktrace)) {
stacktrace = clipboard;
final Project project = ideFrame.getProject();
if (project != null && isStacktrace(stacktrace)) {
final UnscrambleDialog dialog = new UnscrambleDialog(project);
dialog.createNormalizeTextAction().actionPerformed(null);
dialog.doOKAction();
}
}
}
};
if (Patches.SLOW_GETTING_CLIPBOARD_CONTENTS) {
//IDEA's clipboard is synchronized with the system clipboard on frame activation so we need to postpone clipboard processing
new Alarm().addRequest(processClipboard, 300);
}
else {
processClipboard.run();
}
}
@@ -14,24 +14,22 @@ class C {
try (MyResource r = new MyResource()) { r.doSomething(); }
catch (E1 | E2 | E3 ignore) { }
try (new MyResource()) { }
try (MyResource r = new MyResource()) { }
catch (E1 | E3 ignore) { }
MyResource r;
try (<error descr="Unhandled exception from auto-closeable resource: C.E3">r = new MyResource()</error>) { }
try (<error descr="Unhandled exception from auto-closeable resource: C.E3">MyResource r = new MyResource()</error>) { }
catch (E1 e) { }
try (r = <error descr="Unhandled exception: C.E1">new MyResource()</error>) { }
try (MyResource r = <error descr="Unhandled exception: C.E1">new MyResource()</error>) { }
catch (E3 e) { }
try (r = <error descr="Unhandled exception: C.E1">new MyResource()</error>) { }
try (MyResource r = <error descr="Unhandled exception: C.E1">new MyResource()</error>) { }
}
void m2() throws Exception {
try (<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.AutoCloseable'">Object r = new MyResource()</error>) { }
try (<error descr="Incompatible types. Found: 'java.lang.String', required: 'java.lang.AutoCloseable'">"resource"</error>) { }
try (<error descr="Incompatible types. Found: 'java.lang.String', required: 'java.lang.AutoCloseable'">AutoCloseable r = "resource"</error>) { }
}
void m3(int p) throws Exception {
@@ -56,7 +54,7 @@ class C {
MyResource r = null;
try (MyResource <error descr="Variable 'r' is already defined in the scope">r</error> = new MyResource()) { }
try (r = new MyResource()) { }
try (MyResource rr = r) { }
try (MyResource <error descr="Variable 'p' is already defined in the scope">p</error> = new MyResource()) { }
new Runnable() {
@@ -6,35 +6,28 @@ class C {
}
void m1() throws Exception {
MyResource r1;
try (r1 = new MyResource()) {
try (MyResource r1 = new MyResource()) {
System.out.println(r1);
}
try (MyResource r2 = new MyResource()) {
System.out.println(r2);
}
MyResource r3 = new MyResource();
try (MyResource r = r3) {
MyResource r2 = new MyResource();
try (MyResource r = r2) {
System.out.println(r);
System.out.println(r2);
}
}
void m2() throws Exception {
MyResource r1 = <warning descr="Variable 'r1' initializer 'null' is redundant">null</warning>;
try (r1 = new MyResource()) {
System.out.println(r1);
}
// todo: test in IG
//MyResource < warning descr="Local variable 'r1' is redundant">r1</warning> = null;
//try (MyResource r = r1) {
// System.out.println(r);
//}
MyResource r2 = null;
System.out.println(r2);
try (r2 = <warning descr="The value 'new MyResource()' assigned to r2 is never used">new MyResource()</warning>) { }
try (MyResource <warning descr="Variable 'r2' is never used">r2</warning> = new MyResource()) { }
try (MyResource <warning descr="Variable 'r3' is never used">r3</warning> = new MyResource()) { }
MyResource <warning descr="Variable 'r4' is never assigned">r4</warning>;
try (MyResource r = <error descr="Variable 'r4' might not have been initialized">r4</error>) {
MyResource <warning descr="Variable 'r3' is never assigned">r3</warning>;
try (MyResource r = <error descr="Variable 'r3' might not have been initialized">r3</error>) {
System.out.println(r);
}
}
@@ -1,14 +0,0 @@
// "Reuse previous variable 'r' declaration" "true"
import java.io.*;
class a {
static class MyResource implements AutoCloseable {
public void close() { }
}
void m() {
MyResource r;
try (r = new MyResource()) {
}
}
}
@@ -1,14 +0,0 @@
// "Reuse previous variable 'r' declaration" "true"
import java.io.*;
class a {
static class MyResource implements AutoCloseable {
public void close() { }
}
void m() {
MyResource r;
try (MyResource <caret>r = new MyResource()) {
}
}
}
@@ -3,6 +3,8 @@ PsiJavaFile:TryIncomplete10.java
PsiKeyword:try('try')
PsiResourceList:(
PsiJavaToken:LPARENTH('(')
PsiErrorElement:Identifier or type expected
<empty list>
PsiErrorElement:')' expected
<empty list>
PsiCodeBlock
@@ -3,7 +3,7 @@ PsiJavaFile:TryIncomplete11.java
PsiKeyword:try('try')
PsiResourceList:()
PsiJavaToken:LPARENTH('(')
PsiErrorElement:Resource definition expected
PsiErrorElement:Identifier or type expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
@@ -6,8 +6,6 @@ PsiJavaFile:TryIncomplete12.java
PsiErrorElement:Resource definition expected
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiErrorElement:Resource definition expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -5,9 +5,13 @@ PsiJavaFile:TryIncomplete13.java
PsiJavaToken:LPARENTH('(')
PsiModifierList:final
PsiKeyword:final('final')
PsiErrorElement:Identifier or type expected
PsiErrorElement:Type expected
<empty list>
PsiWhiteSpace(' ')
PsiTypeElement:
<empty list>
PsiErrorElement:Identifier expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -3,8 +3,12 @@ PsiJavaFile:TryIncomplete14.java
PsiKeyword:try('try')
PsiResourceList:(int)
PsiJavaToken:LPARENTH('(')
PsiErrorElement:Resource definition expected
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiErrorElement:Identifier expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -3,19 +3,18 @@ PsiJavaFile:TryIncomplete15.java
PsiKeyword:try('try')
PsiResourceList:(R r)
PsiJavaToken:LPARENTH('(')
PsiResource:r
PsiLocalVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiErrorElement:'=' expected
<empty list>
PsiResourceVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiErrorElement:'=' expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -3,21 +3,20 @@ PsiJavaFile:TryIncomplete16.java
PsiKeyword:try('try')
PsiResourceList:(R r =)
PsiJavaToken:LPARENTH('(')
PsiResource:r
PsiLocalVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiErrorElement:Expression expected
<empty list>
PsiResourceVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiErrorElement:Expression expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -1,27 +1,27 @@
PsiJavaFile:TryIncomplete17.java
PsiTryStatement
PsiKeyword:try('try')
PsiResourceList:(R r = 0;)
PsiResourceList:(R r = 0;;)
PsiJavaToken:LPARENTH('(')
PsiResource:r
PsiLocalVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiResourceVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:SEMICOLON(';')
PsiErrorElement:Identifier or type expected
PsiErrorElement:Resource definition expected
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -3,22 +3,21 @@ PsiJavaFile:TryNormal4.java
PsiKeyword:try('try')
PsiResourceList:(R r = 0)
PsiJavaToken:LPARENTH('(')
PsiResource:r
PsiLocalVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiResourceVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -3,40 +3,38 @@ PsiJavaFile:TryNormal5.java
PsiKeyword:try('try')
PsiResourceList:(R1 r1 = 1; R2 r2 = 2)
PsiJavaToken:LPARENTH('(')
PsiResource:r1
PsiLocalVariable:r1
PsiModifierList:
<empty list>
PsiTypeElement:R1
PsiJavaCodeReferenceElement:R1
PsiIdentifier:R1('R1')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r1('r1')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiResourceVariable:r1
PsiModifierList:
<empty list>
PsiTypeElement:R1
PsiJavaCodeReferenceElement:R1
PsiIdentifier:R1('R1')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r1('r1')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiResource:r2
PsiLocalVariable:r2
PsiModifierList:
<empty list>
PsiTypeElement:R2
PsiJavaCodeReferenceElement:R2
PsiIdentifier:R2('R2')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r2('r2')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiResourceVariable:r2
PsiModifierList:
<empty list>
PsiTypeElement:R2
PsiJavaCodeReferenceElement:R2
PsiIdentifier:R2('R2')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r2('r2')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -1,13 +1,24 @@
PsiJavaFile:TryNormal6.java
PsiTryStatement
PsiKeyword:try('try')
PsiResourceList:(r)
PsiResourceList:(R r = 0;)
PsiJavaToken:LPARENTH('(')
PsiResource:
PsiReferenceExpression:r
PsiReferenceParameterList
<empty list>
PsiIdentifier:r('r')
PsiResourceVariable:r
PsiModifierList:
<empty list>
PsiTypeElement:R
PsiJavaCodeReferenceElement:R
PsiIdentifier:R('R')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:r('r')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:SEMICOLON(';')
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
@@ -1,19 +0,0 @@
PsiJavaFile:TryNormal7.java
PsiTryStatement
PsiKeyword:try('try')
PsiResourceList:(r; null)
PsiJavaToken:LPARENTH('(')
PsiResource:
PsiReferenceExpression:r
PsiReferenceParameterList
<empty list>
PsiIdentifier:r('r')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiResource:
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiJavaToken:RBRACE('}')
@@ -32,7 +32,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
@Override
protected LocalInspectionTool[] configureLocalInspectionTools() {
return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection(), new DefUseInspection()};
return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection()};
}
public void testDuplicateAnnotations() throws Exception {
@@ -194,6 +194,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
}
public void testTryWithResourcesWarn() throws Exception {
enableInspectionTool(new DefUseInspection());
doTest(true, false);
}
@@ -122,8 +122,7 @@ public class StatementParserTest extends JavaParsingTestCase {
public void testTryNormal3() { doParserTestJDK7("try{}catch(A|B e){}"); }
public void testTryNormal4() { doParserTestJDK7("try(R r = 0){}"); }
public void testTryNormal5() { doParserTestJDK7("try(R1 r1 = 1; R2 r2 = 2){}"); }
public void testTryNormal6() { doParserTestJDK7("try(r){}"); }
public void testTryNormal7() { doParserTestJDK7("try(r; null){}"); }
public void testTryNormal6() { doParserTestJDK7("try(R r = 0;){}"); }
public void testTryIncomplete0() { doParserTest("try"); }
public void testTryIncomplete1() { doParserTest("try{}"); }
public void testTryIncomplete2() { doParserTest("try{}catch"); }
@@ -141,7 +140,7 @@ public class StatementParserTest extends JavaParsingTestCase {
public void testTryIncomplete14() { doParserTestJDK7("try(int){}"); }
public void testTryIncomplete15() { doParserTestJDK7("try(R r){}"); }
public void testTryIncomplete16() { doParserTestJDK7("try(R r =){}"); }
public void testTryIncomplete17() { doParserTestJDK7("try(R r = 0;){}"); }
public void testTryIncomplete17() { doParserTestJDK7("try(R r = 0;;){}"); }
public void testWhileNormal() { doParserTest("while (true) foo();"); }
public void testWhileIncomplete0() { doParserTest("while"); }
@@ -17,6 +17,9 @@ package com.intellij.psi;
import com.intellij.lang.FileASTNode;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.impl.DebugUtil;
@@ -39,6 +42,12 @@ public class JavaStubBuilderTest extends LightIdeaTestCase {
public void setUp() throws Exception {
super.setUp();
doTest("@interface A { int i() default 42; }\n class C { void m(int p) throws E { } }", null); // warm up
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
}
@Override
protected Sdk getProjectJDK() {
return JavaSdkImpl.getMockJdk17();
}
public void testEmpty() {
@@ -255,6 +264,9 @@ public class JavaStubBuilderTest extends LightIdeaTestCase {
" int local = 0;\n" +
" for (int loop = 0; loop < 10; loop++) ;\n" +
" try (Resource r = new Resource()) { }\n" +
" try (Resource r = new Resource() {\n" +
" public void close() { }\n" +
" }) { }\n" +
" }\n" +
"}",
@@ -269,32 +281,34 @@ public class JavaStubBuilderTest extends LightIdeaTestCase {
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" +
" TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" +
" PARAMETER_LIST:PsiParameterListStub\n" +
" THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n");
" THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" +
" ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=Resource]\n" +
" METHOD:PsiMethodStub[close:void]\n" +
" MODIFIER_LIST:PsiModifierListStub[mask=1]\n" +
" TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" +
" PARAMETER_LIST:PsiParameterListStub\n" +
" THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n");
}
public void testNonListParameters() {
withLevel(LanguageLevel.JDK_1_7, new Runnable() {
@Override public void run() {
doTest("class C {\n" +
" {\n" +
" for (int i : arr) ;\n" +
" try { }\n" +
" catch (Throwable t) { }\n" +
" catch (E1|E2 e) { }\n" +
" }\n" +
"}",
doTest("class C {\n" +
" {\n" +
" for (int i : arr) ;\n" +
" try { }\n" +
" catch (Throwable t) { }\n" +
" catch (E1|E2 e) { }\n" +
" }\n" +
"}",
"PsiJavaFileStub []\n" +
" IMPORT_LIST:PsiImportListStub\n" +
" CLASS:PsiClassStub[name=C fqn=C]\n" +
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" +
" TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" +
" EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" +
" IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" +
" CLASS_INITIALIZER:PsiClassInitializerStub\n" +
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n");
}
});
"PsiJavaFileStub []\n" +
" IMPORT_LIST:PsiImportListStub\n" +
" CLASS:PsiClassStub[name=C fqn=C]\n" +
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" +
" TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" +
" EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" +
" IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" +
" CLASS_INITIALIZER:PsiClassInitializerStub\n" +
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n");
}
public void testSOEProof() {
@@ -300,8 +300,8 @@ public abstract class JavaElementVisitor extends PsiElementVisitor {
visitElement(resourceList);
}
public void visitResource(PsiResource resource) {
visitElement(resource);
public void visitResourceVariable(PsiResourceVariable resourceVariable) {
visitLocalVariable(resourceVariable);
}
public void visitTypeElement(PsiTypeElement type) {
@@ -125,7 +125,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade {
* @throws com.intellij.util.IncorrectOperationException if the text is not a valid resource definition.
*/
@NotNull
PsiResource createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException;
PsiResourceVariable createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException;
/**
* Creates a Java type from the specified text.
@@ -1,39 +0,0 @@
/*
* Copyright 2000-2011 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 com.intellij.psi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a resource list of try-with-resources statement (automatic resource management) introduced in JDK 7.
*
* @see PsiResourceList#getResources()
* @since 10.5.
*/
public interface PsiResource extends PsiElement {
/**
* Returns main element of the resource.
* It may be PsiLocalVariable, PsiAssignmentExpression, or other instance of PsiExpression.
*
* @return resource element.
*/
@NotNull
PsiElement getResourceElement();
@Nullable
PsiType getType();
}
@@ -27,5 +27,5 @@ import java.util.List;
*/
public interface PsiResourceList extends PsiElement {
@NotNull
List<PsiResource> getResources();
List<PsiResourceVariable> getResourceVariables();
}
@@ -17,12 +17,13 @@ package com.intellij.psi;
import org.jetbrains.annotations.NotNull;
public interface PsiScopedLocalVariable extends PsiLocalVariable {
/**
* Returns the element or elements (method, "for" statement or try block) in which the variable is declared.
*
* @return the declaration scope for the variable.
*/
/**
* Represents a resource variable of try-with-resources statement (automatic resource management) introduced in JDK 7.
*
* @see PsiResourceList#getResourceVariables()
* @since 10.5.
*/
public interface PsiResourceVariable extends PsiLocalVariable {
@NotNull
PsiElement[] getDeclarationScope();
}
@@ -29,8 +29,6 @@ import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.editor.colors.EditorFontType;
import com.intellij.openapi.editor.event.SelectionEvent;
import com.intellij.openapi.editor.event.SelectionListener;
@@ -108,7 +106,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec
private boolean myIsReplace;
private boolean myListeningSelection = false;
private boolean myToChangeSelection = true;
private SearchResults mySearchResults;
private Balloon myOptionsBalloon;
@@ -129,59 +126,40 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec
int count = sr.getActualFound();
if (mySearchField.getText().isEmpty()) {
nothingToSearchFor();
return;
}
} else {
if (count <= mySearchResults.getMatchesLimit()) {
myClickToHighlightLabel.setVisible(false);
if (count <= mySearchResults.getMatchesLimit()) {
myClickToHighlightLabel.setVisible(false);
if (count > 0) {
setRegularBackground();
if (count > 1) {
myMatchInfoLabel.setText(count + " matches");
if (count > 0) {
setRegularBackground();
if (count > 1) {
myMatchInfoLabel.setText(count + " matches");
}
else {
myMatchInfoLabel.setText("1 match");
}
}
else {
myMatchInfoLabel.setText("1 match");
setNotFoundBackground();
myMatchInfoLabel.setText("No matches");
}
}
else {
setNotFoundBackground();
myMatchInfoLabel.setText("No matches");
setRegularBackground();
myMatchInfoLabel.setText("More than " + mySearchResults.getMatchesLimit() + " matches");
myClickToHighlightLabel.setVisible(true);
boldMatchInfo();
}
}
else {
setRegularBackground();
myMatchInfoLabel.setText("More than " + mySearchResults.getMatchesLimit() + " matches");
myClickToHighlightLabel.setVisible(true);
boldMatchInfo();
}
updateSelection();
updateExcludeStatus();
}
@Override
public void cursorMoved() {
updateSelection();
updateExcludeStatus();
}
private void updateSelection() {
SelectionModel selection = myEditor.getSelectionModel();
if (myToChangeSelection && (mySelectionOnly == null || !mySelectionOnly.isSelected())) {
LiveOccurrence cursor = mySearchResults.getCursor();
if (cursor != null) {
TextRange range = cursor.getPrimaryRange();
selection.setSelection(range.getStartOffset(), range.getEndOffset());
myEditor.getCaretModel().moveToOffset(range.getEndOffset());
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
myToChangeSelection = false;
}
}
@Override
public void editorChanged(SearchResults sr, Editor oldEditor) { }
@@ -580,14 +558,13 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec
}
private void searchBackward() {
moveCursor(false);
moveCursor(SearchResults.Direction.UP);
addCurrentTextToRecents();
}
private void searchForward() {
moveCursor(true);
moveCursor(SearchResults.Direction.DOWN);
addCurrentTextToRecents();
}
@@ -603,13 +580,8 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec
updateResults(true);
}
public void moveCursor(boolean forwardOrBackward) {
myToChangeSelection = true;
if (forwardOrBackward) {
mySearchResults.nextOccurrence();
} else {
mySearchResults.prevOccurrence();
}
public void moveCursor(SearchResults.Direction direction) {
myLivePreviewController.moveCursor(direction, true);
}
public void replaceCurrent() {
@@ -660,7 +632,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec
myEditor.getDocument().addDocumentListener(myDocumentListener);
if (myLivePreview != null) {
myLivePreviewController.updateInBackground(mySearchResults.getFindModel());
myLivePreviewController.updateInBackground(mySearchResults.getFindModel(), false);
}
}
@@ -727,11 +699,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec
model.setGlobal(!mySelectionOnly.isSelected());
model.setPreserveCase(myPreserveCase.isEnabled() && myPreserveCase.isSelected());
}
if (!myToChangeSelection) {
myToChangeSelection = allowedToChangedEditorSelection;
}
myLivePreviewController.updateInBackground(model);
myLivePreviewController.updateInBackground(model, allowedToChangedEditorSelection);
}
}
@@ -1006,13 +974,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec
mySearchField.requestFocus();
}
@Override
public TextRange performReplace(LiveOccurrence occurrence, String replacement, Editor editor) {
myToChangeSelection = true;
return super
.performReplace(occurrence, replacement, editor); //To change body of overridden methods use File | Settings | File Templates.
}
public void performReplace() {
String replacement = getStringToReplace(myEditor, mySearchResults.getCursor());
performReplace(mySearchResults.getCursor(), replacement, myEditor);
@@ -766,7 +766,7 @@ public class FindUtil {
}
});
}
}, null, document);
}, null, null);
return startOffset + converted.length();
}
@@ -24,6 +24,7 @@ import com.intellij.codeInsight.hint.HintManagerImpl;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.find.*;
import com.intellij.find.findUsages.FindUsagesManager;
import com.intellij.find.impl.livePreview.SearchResults;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageParserDefinitions;
import com.intellij.lang.ParserDefinition;
@@ -655,7 +656,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo
}
}
private boolean tryToFindNextUsageViaEditorSearchComponent(Editor editor, boolean forwardOrBackward) {
private boolean tryToFindNextUsageViaEditorSearchComponent(Editor editor, SearchResults.Direction forwardOrBackward) {
if (editor.getHeaderComponent() instanceof EditorSearchComponent) {
EditorSearchComponent searchComponent = (EditorSearchComponent)editor.getHeaderComponent();
if (searchComponent.hasMatches()) {
@@ -670,7 +671,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo
if (fileEditor instanceof TextEditor) {
TextEditor textEditor = (TextEditor)fileEditor;
Editor editor = textEditor.getEditor();
if (tryToFindNextUsageViaEditorSearchComponent(editor, true)) {
if (tryToFindNextUsageViaEditorSearchComponent(editor, SearchResults.Direction.DOWN)) {
return true;
}
FindModel model = getFindNextModel(editor);
@@ -689,7 +690,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo
if (fileEditor instanceof TextEditor) {
TextEditor textEditor = (TextEditor)fileEditor;
Editor editor = textEditor.getEditor();
if (tryToFindNextUsageViaEditorSearchComponent(editor, false)) {
if (tryToFindNextUsageViaEditorSearchComponent(editor, SearchResults.Direction.UP)) {
return true;
}
FindModel model = getFindNextModel(editor);
@@ -6,6 +6,8 @@ import com.intellij.find.FindUtil;
import com.intellij.find.impl.FindResultImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.util.Alarm;
@@ -13,7 +15,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil.ReplaceDelegate {
public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil.ReplaceDelegate, SearchResults.SearchResultsListener {
private static final String EMPTY_STRING_DISPLAY_TEXT = "<Empty string>";
@@ -26,6 +28,48 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil
private SearchResults mySearchResults;
private LivePreview myLivePreview;
private boolean myToChangeSelection = true;
private void updateSelection() {
Editor editor = mySearchResults.getEditor();
SelectionModel selection = editor.getSelectionModel();
FindModel findModel = mySearchResults.getFindModel();
if (myToChangeSelection && findModel.isGlobal()) {
LiveOccurrence cursor = mySearchResults.getCursor();
if (cursor != null) {
TextRange range = cursor.getPrimaryRange();
selection.setSelection(range.getStartOffset(), range.getEndOffset());
editor.getCaretModel().moveToOffset(range.getEndOffset());
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
myToChangeSelection = false;
}
}
@Override
public void searchResultsUpdated(SearchResults sr) {
updateSelection();
}
@Override
public void editorChanged(SearchResults sr, Editor oldEditor) {}
@Override
public void cursorMoved() {
updateSelection();
}
public void moveCursor(SearchResults.Direction direction, boolean toChangeSelection) {
myToChangeSelection = toChangeSelection;
if (direction == SearchResults.Direction.UP) {
mySearchResults.prevOccurrence();
} else {
mySearchResults.nextOccurrence();
}
}
public interface ReplaceListener {
void replacePerformed(LiveOccurrence occurrence, final String replacement, final Editor editor);
void replaceAllPerformed(Editor e);
@@ -43,6 +87,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil
public LivePreviewControllerBase(SearchResults searchResults, LivePreview livePreview) {
mySearchResults = searchResults;
mySearchResults.addListener(this);
myLivePreview = livePreview;
myLivePreview.setDelegate(this);
}
@@ -55,7 +100,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil
myUserActivityDelay = userActivityDelay;
}
public void updateInBackground(final FindModel findModel) {
public void updateInBackground(final FindModel findModel, boolean allowedToChangedEditorSelection) {
myLivePreviewAlarm.cancelAllRequests();
if (findModel == null) return;
Runnable request = new Runnable() {
@@ -69,6 +114,9 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil
} else {
myLivePreviewAlarm.addRequest(request, myUserActivityDelay);
}
if (allowedToChangedEditorSelection) {
myToChangeSelection = true;
}
}
@Override
@@ -99,6 +147,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil
@Nullable
@Override
public TextRange performReplace(final LiveOccurrence occurrence, final String replacement, final Editor editor) {
myToChangeSelection = true;
TextRange range = occurrence.getPrimaryRange();
FindModel findModel = mySearchResults.getFindModel();
TextRange result = null;
@@ -19,6 +19,8 @@ import java.util.List;
public class SearchResults {
public enum Direction {UP, DOWN}
private int myActualFound = 0;
private List<SearchResultsListener> myListeners = new ArrayList<SearchResultsListener>();
@@ -293,6 +295,8 @@ public class SearchResults {
for (LiveOccurrence searchResult : getOccurrences()) {
if (searchResult.getPrimaryRange().intersects(oldCursorRange)) {
mayBeOldCursor = searchResult;
}
if (searchResult.getPrimaryRange().equals(oldCursorRange)) {
break;
}
}
@@ -658,7 +658,8 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
return markupModel;
}
if (project.isDisposed()) {
final DocumentMarkupModelManager documentMarkupModelManager = project.isDisposed() ? null : DocumentMarkupModelManager.getInstance(project);
if (documentMarkupModelManager == null || documentMarkupModelManager.isDisposed() || project.isDisposed()) {
return new EmptyMarkupModel(this);
}
@@ -669,15 +670,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
if (model == null) {
model = new MarkupModelImpl(this);
myProjectToMarkupModelMap.put(project, model);
Disposer.register(project, new Disposable() {
@Override
public void dispose() {
MarkupModelImpl removed = myProjectToMarkupModelMap.remove(project);
if (removed != null) {
removed.dispose();
}
}
});
documentMarkupModelManager.registerDocument(this);
}
}
}
@@ -685,6 +678,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
return model;
}
void removeMarkupModel(@NotNull Project project) {
MarkupModelImpl removed = myProjectToMarkupModelMap.remove(project);
if (removed != null) {
removed.dispose();
}
}
public void setCyclicBufferSize(int bufferSize) {
myText.setBufferSize(bufferSize);
}
@@ -0,0 +1,66 @@
/*
* Copyright 2000-2011 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 com.intellij.openapi.editor.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.containers.WeakList;
import org.jetbrains.annotations.NotNull;
/**
* @author max
*/
public class DocumentMarkupModelManager extends AbstractProjectComponent {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentMarkupModelManager");
private final WeakList<DocumentImpl> myDocumentSet = new WeakList<DocumentImpl>();
private volatile boolean myDisposed;
public static DocumentMarkupModelManager getInstance(Project project) {
return project.getComponent(DocumentMarkupModelManager.class);
}
public DocumentMarkupModelManager(@NotNull Project project) {
super(project);
Disposer.register(project, new Disposable() {
@Override
public void dispose() {
cleanupProjectMarkups();
}
});
}
public void registerDocument(DocumentImpl document) {
LOG.assertTrue(!myDisposed);
myDocumentSet.add(document);
}
public boolean isDisposed() {
return myDisposed;
}
private void cleanupProjectMarkups() {
if (!myDisposed) {
myDisposed = true;
for (DocumentImpl document : myDocumentSet.toStrongList()) {
document.removeMarkupModel(myProject);
}
}
}
}
@@ -19,6 +19,9 @@
<!--<component>-->
<!--<implementation-class>com.intellij.jsp.impl.browserprofile.BrowserProfileProvider</implementation-class>-->
<!--</component>-->
<component>
<implementation-class>com.intellij.openapi.editor.impl.DocumentMarkupModelManager</implementation-class>
</component>
<component>
<implementation-class>com.intellij.openapi.fileEditor.impl.EditorHistoryManager</implementation-class>
<option name="workspace" value="true"/>
@@ -32,4 +35,4 @@
</component>
</project-components>
</components>
</components>
@@ -83,6 +83,17 @@ public class MostlySingularMultiMap<K, V> {
return true;
}
public int size() {
return myMap.size();
}
public int valuesForKey(K key) {
Object current = myMap.get(key);
if (current == null) return 0;
if (current instanceof Object[]) return ((Object[])current).length;
return 1;
}
@NotNull
public Iterable<V> get(K name) {
final Object value = myMap.get(name);
@@ -0,0 +1,153 @@
/*
* Copyright 2000-2011 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.
*/
/*
* @author max
*/
package com.intellij.util.io;
import java.io.DataInput;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
public class CompactDataInput implements DataInput {
private final InputStream in;
private final byte[] readBuffer = IOUtil.allocReadWriteUTFBuffer();
public CompactDataInput(InputStream in) {
this.in = in;
}
@Override
public void readFully(byte[] b) throws IOException {
readFully(b, 0, b.length);
}
@Override
public void readFully(byte[] b, int off, int len) throws IOException {
if (len < 0)
throw new IndexOutOfBoundsException();
int n = 0;
while (n < len) {
int count = in.read(b, off + n, len - n);
if (count < 0)
throw new EOFException();
n += count;
}
}
@Override
public int skipBytes(int n) throws IOException {
int total = 0;
int cur = 0;
while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) {
total += cur;
}
return total;
}
@Override
public boolean readBoolean() throws IOException {
int ch = in.read();
if (ch < 0)
throw new EOFException();
return (ch != 0);
}
@Override
public byte readByte() throws IOException {
int ch = in.read();
if (ch < 0)
throw new EOFException();
return (byte)(ch);
}
@Override
public int readUnsignedByte() throws IOException {
int ch = in.read();
if (ch < 0)
throw new EOFException();
return ch;
}
@Override
public short readShort() throws IOException {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new EOFException();
return (short)((ch1 << 8) + (ch2 << 0));
}
@Override
public int readUnsignedShort() throws IOException {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new EOFException();
return (ch1 << 8) + (ch2 << 0);
}
@Override
public char readChar() throws IOException {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new EOFException();
return (char)((ch1 << 8) + (ch2 << 0));
}
@Override
public int readInt() throws IOException {
return DataInputOutputUtil.readINT(this);
}
@Override
public long readLong() throws IOException { // TODO: Make longs actually compact
readFully(readBuffer, 0, 8);
return (((long)readBuffer[0] << 56) +
((long)(readBuffer[1] & 255) << 48) +
((long)(readBuffer[2] & 255) << 40) +
((long)(readBuffer[3] & 255) << 32) +
((long)(readBuffer[4] & 255) << 24) +
((readBuffer[5] & 255) << 16) +
((readBuffer[6] & 255) << 8) +
((readBuffer[7] & 255) << 0));
}
@Override
public float readFloat() throws IOException {
return Float.intBitsToFloat(readInt());
}
@Override
public double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
@Override
public String readLine() throws IOException {
throw new UnsupportedOperationException("readLine is not implemented!");
}
@Override
public String readUTF() throws IOException {
return IOUtil.readUTFFast(readBuffer, this);
}
}
@@ -0,0 +1,121 @@
/*
* Copyright 2000-2011 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.
*/
/*
* @author max
*/
package com.intellij.util.io;
import java.io.DataOutput;
import java.io.IOException;
import java.io.OutputStream;
public class CompactDataOutput implements DataOutput {
private final OutputStream out;
private final byte[] writeBuffer = IOUtil.allocReadWriteUTFBuffer();
public CompactDataOutput(OutputStream out) {
this.out = out;
}
@Override
public void write(int b) throws IOException {
out.write(b);
}
@Override
public void write(byte[] b) throws IOException {
out.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
}
@Override
public void writeBoolean(boolean v) throws IOException {
out.write(v ? 1 : 0);
}
@Override
public void writeByte(int v) throws IOException {
out.write(v);
}
@Override
public void writeShort(int v) throws IOException {
out.write((v >>> 8) & 0xFF);
out.write(v & 0xFF);
}
@Override
public void writeChar(int v) throws IOException {
out.write((v >>> 8) & 0xFF);
out.write(v & 0xFF);
}
@Override
public void writeInt(int val) throws IOException {
DataInputOutputUtil.writeINT(this, val);
}
@Override
public void writeLong(long v) throws IOException { // TODO: Make longs actually compact
writeBuffer[0] = (byte)(v >>> 56);
writeBuffer[1] = (byte)(v >>> 48);
writeBuffer[2] = (byte)(v >>> 40);
writeBuffer[3] = (byte)(v >>> 32);
writeBuffer[4] = (byte)(v >>> 24);
writeBuffer[5] = (byte)(v >>> 16);
writeBuffer[6] = (byte)(v >>> 8);
writeBuffer[7] = (byte)(v >>> 0);
out.write(writeBuffer, 0, 8);
}
@Override
public void writeFloat(float v) throws IOException {
writeInt(Float.floatToIntBits(v));
}
@Override
public void writeDouble(double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}
@Override
public void writeBytes(String s) throws IOException {
int len = s.length();
for (int i = 0 ; i < len ; i++) {
out.write((byte)s.charAt(i));
}
}
@Override
public void writeChars(String s) throws IOException {
int len = s.length();
for (int i = 0 ; i < len ; i++) {
int v = s.charAt(i);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
}
}
@Override
public void writeUTF(String s) throws IOException {
IOUtil.writeUTFFast(writeBuffer, this, s);
}
}
@@ -889,7 +889,7 @@ octal.literal.problem.descriptor=Octal integer <code>#ref</code> #loc
implicit.call.to.super.problem.descriptor=Implicit call to super() <code>#ref</code> #loc
negated.if.else.problem.descriptor=<code>#ref</code> statement with negated condition #loc
negated.conditional.problem.descriptor=Conditional expression with negated condition #loc
confusing.else.problem.descriptor=<code>#ref</code> branch may be unwrapped, as the if branch never completes #loc
confusing.else.problem.descriptor=<code>#ref</code> branch may be unwrapped, as the 'if' branch never completes #loc
switch.statement.with.confusing.declaration.problem.descriptor=Local variable <code>#ref</code> declared in one 'switch' branch and used in another #loc
raw.use.of.parameterized.type.problem.descriptor=Raw use of parameterized class <code>#ref</code> #loc
final.class.problem.descriptor=Class declared <code>#ref</code> #loc
@@ -1856,3 +1856,4 @@ if.can.be.switch.enum.option=Suggest switch on enum
unnecessarily.qualified.inner.class.access.option=Ignore references to foreign inner classes
unqualified.inner.class.access.option=Ignore references to local inner classes
try.with.identical.catches.quickfix=Collapse catch blocks into multi-catch
confusing.else.option=<html>Also report when there are no more statements after the 'if' statement</html>
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package com.siyeh.ig.controlflow;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -29,28 +30,45 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class ConfusingElseInspection extends BaseInspection {
@SuppressWarnings({"PublicField"})
public boolean reportWhenNoStatementFollow = false;
@Override
@NotNull
public String getID() {
return "ConfusingElseBranch";
}
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message("confusing.else.display.name");
}
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"confusing.else.problem.descriptor");
}
@Override
public JComponent createOptionsPanel() {
return new SingleCheckboxOptionsPanel(
InspectionGadgetsBundle.message("confusing.else.option"),
this, "reportWhenNoStatementFollow");
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new ConfusingElseVisitor();
}
@Override
@Nullable
protected InspectionGadgetsFix buildFix(Object... infos) {
return new ConfusingElseFix();
@@ -64,6 +82,7 @@ public class ConfusingElseInspection extends BaseInspection {
"confusing.else.unwrap.quickfix");
}
@Override
public void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
final PsiElement ifKeyword = descriptor.getPsiElement();
@@ -108,10 +127,11 @@ public class ConfusingElseInspection extends BaseInspection {
}
}
private static class ConfusingElseVisitor
private class ConfusingElseVisitor
extends BaseInspectionVisitor {
@Override public void visitIfStatement(@NotNull PsiIfStatement statement) {
@Override public void visitIfStatement(
@NotNull PsiIfStatement statement) {
super.visitIfStatement(statement);
final PsiStatement thenBranch = statement.getThenBranch();
if (thenBranch == null) {
@@ -127,16 +147,17 @@ public class ConfusingElseInspection extends BaseInspection {
if (ControlFlowUtils.statementMayCompleteNormally(thenBranch)) {
return;
}
final PsiStatement nextStatement =
PsiTreeUtil.getNextSiblingOfType(statement,
PsiStatement.class);
if (nextStatement == null) {
return;
}
if (!ControlFlowUtils.statementMayCompleteNormally(elseBranch)) {
return;
//protecting against an edge case where both branches return
// and are followed by a case label
if (reportWhenNoStatementFollow) {
final PsiStatement nextStatement = getNextStatement(statement);
if (nextStatement == null) {
return;
}
if (!ControlFlowUtils.statementMayCompleteNormally(
elseBranch)) {
return;
// protecting against an edge case where both branches return
// and are followed by a case label
}
}
final PsiElement elseToken = statement.getElseElement();
if (elseToken == null) {
@@ -144,5 +165,23 @@ public class ConfusingElseInspection extends BaseInspection {
}
registerError(elseToken);
}
private PsiStatement getNextStatement(PsiIfStatement statement) {
while (true) {
final PsiElement parent = statement.getParent();
if (parent instanceof PsiIfStatement) {
final PsiIfStatement parentIfStatement =
(PsiIfStatement) parent;
final PsiStatement elseBranch =
parentIfStatement.getElseBranch();
if (elseBranch == statement) {
statement = parentIfStatement;
continue;
}
}
return PsiTreeUtil.getNextSiblingOfType(statement,
PsiStatement.class);
}
}
}
}
@@ -157,12 +157,10 @@ public class IfStatementWithIdenticalBranchesInspection
private static class IfStatementWithIdenticalBranchesVisitor
extends BaseInspectionVisitor{
private static final int LIMIT_DEPTH = 20; // Dirty fix for 'squared' algorithm.
@Override public void visitIfStatement(
@NotNull PsiIfStatement ifStatement){
super.visitIfStatement(ifStatement);
PsiStatement elseBranch = ifStatement.getElseBranch();
final PsiStatement elseBranch = ifStatement.getElseBranch();
final PsiStatement thenBranch = ifStatement.getThenBranch();
if (thenBranch == null) {
return;
@@ -175,11 +173,7 @@ public class IfStatementWithIdenticalBranchesInspection
new DuplicatesFinder(new PsiElement[]{thenBranch},
inputVariables, null,
Collections.<PsiVariable>emptyList());
int depth = 0;
while (elseBranch instanceof PsiIfStatement) {
if (depth++ > LIMIT_DEPTH) {
break;
}
if (elseBranch instanceof PsiIfStatement) {
final PsiIfStatement statement =
(PsiIfStatement) elseBranch;
final PsiStatement branch = statement.getThenBranch();
@@ -191,7 +185,6 @@ public class IfStatementWithIdenticalBranchesInspection
registerStatementError(ifStatement, statement);
return;
}
elseBranch = statement.getElseBranch();
}
if (elseBranch == null) {
checkIfStatementWithoutElseBranch(ifStatement);
@@ -1,9 +1,14 @@
<html>
<body>
This inspection reports confusing <b>else</b> branches. Confusing <b>else</b>
branches are branches of <b>if</b> statements whose <b>if</b> branch cannot complete normally and
which are followed by other statements. In these cases, the statements following the
<b>if</b> statement may be moved into the <b>else</b> branch, for increased clarity.
This inspection reports confusing <b>else</b> branches. <b>else</b> branches are confusing
when the <b>if</b> statement is followed by other statements and the <b>if</b> branch
cannot complete normally, for example because it ends with a <b>return</b> statement. In these
cases the statements in the <b>else</b> can be moved after the <b>if</b> statement and
the <b>else</b> branch removed.
<p>
Use the checkbox below to also report <b>else</b> branches of <b>if</b> statements whose
<b>if</b> branch cannot complete normally and which are not followed by more statements,
similar to the Redundant Else intention.
<p>
<small>Powered by InspectionGadgets</small>
</body>
@@ -1,26 +0,0 @@
package com.siyeh.igtest.confusing;
public class ConfusingElseInspection
{
public static void main(String[] args)
{
if(foo())
{
return;
}
else
{
System.out.println("ConfusingElseInspection.main");
}
bar();
}
private static void bar()
{
}
private static boolean foo()
{
return true;
}
}
@@ -0,0 +1,43 @@
package com.siyeh.igtest.controlflow.confusing_else;
public class ConfusingElse {
public static void main(String[] args) {
if (foo()) {
return;
} else {
System.out.println("ConfusingElseInspection.main");
}
bar();
}
private static void bar() {
}
private static boolean foo() {
return true;
}
void two(boolean b) {
if (foo()) {
} else if (b) {
return;
} else {
}
bar();
}
void three(boolean b) {
switch (3) {
case 2:
if (foo()) {
return;
} else {
return;
}
case 3:
}
}
}
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>ConfusingElse.java</file>
<line>8</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Confusing 'else' branch</problem_class>
<description>&lt;code&gt;else&lt;/code&gt; branch may be unwrapped, as the if branch never completes #loc</description>
</problem>
<problem>
<file>ConfusingElse.java</file>
<line>26</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Confusing 'else' branch</problem_class>
<description>&lt;code&gt;else&lt;/code&gt; branch may be unwrapped, as the if branch never completes #loc</description>
</problem>
</problems>
@@ -35,20 +35,6 @@
<description>&lt;code&gt;if&lt;/code&gt; statement with identical branches #loc</description>
</problem>
<problem>
<file>IfStatementWithIdenticalBranches.java</file>
<line>71</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'if' statement with identical branches</problem_class>
<description>&lt;code&gt;if&lt;/code&gt; statement with identical branches #loc</description>
</problem>
<problem>
<file>IfStatementWithIdenticalBranches.java</file>
<line>82</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'if' statement with identical branches</problem_class>
<description>&lt;code&gt;if&lt;/code&gt; statement with identical branches #loc</description>
</problem>
<problem>
<file>IfStatementWithIdenticalBranches.java</file>
<line>92</line>
@@ -0,0 +1,12 @@
package com.siyeh.ig.controlflow;
import com.IGInspectionTestCase;
public class ConfusingElseInspectionTest
extends IGInspectionTestCase {
public void test() throws Exception {
doTest("com/siyeh/igtest/controlflow/confusing_else",
new ConfusingElseInspection());
}
}