blob: 159d7c7bc9a70d8ebc5db2fcf17a1245d5ac1a87 [file] [log] [blame]
/*
* Copyright 2000-2013 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.cache.impl;
import com.intellij.lang.java.JavaParserDefinition;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.impl.source.PsiJavaFileImpl;
import com.intellij.psi.impl.source.tree.StdTokenSets;
import com.intellij.testFramework.PsiTestCase;
import com.intellij.lexer.Lexer;
import com.intellij.lexer.FilterLexer;
import java.io.File;
import java.util.List;
import java.util.ArrayList;
/**
* @author dsl
*/
public class InnerClassesScannerTest extends PsiTestCase {
public void testClassWithGenericParameters() throws Exception { doTest(); }
public void testNewInsideNew() throws Exception { doTest(); }
private void doTest() throws Exception {
configureByFileWithMarker(
PathManagerEx.getTestDataPath() + "/psi/repositoryUse/innerClassesScanner/".replace('/', File.separatorChar) + getTestName(false) + ".java",
"");
final List<PsiClass> list = getInnerClasses(((PsiJavaFile)myFile).getClasses()[0].getMethods()[0], myFile.getViewProvider().getContents());
assertTrue(list != null && list.size() == 1);
}
private static List<PsiClass> getInnerClasses(PsiElement psiElement, final CharSequence fileBuffer) {
final Ref<ArrayList<PsiClass>> ourList = new Ref<ArrayList<PsiClass>>();
ourList.set(null);
if (psiElement != null && mayContainClassesInside(psiElement, fileBuffer)) {
psiElement.accept(new JavaRecursiveElementWalkingVisitor() {
@Override public void visitClass(PsiClass aClass) {
if (ourList.isNull()) ourList.set(new ArrayList<PsiClass>());
ourList.get().add(aClass);
}
@Override public void visitTypeParameter(PsiTypeParameter classParameter) {
// just skip (because type parameter is class - bad!)
}
});
}
return ourList.get();
}
private static boolean mayContainClassesInside(PsiElement psiElement, final CharSequence fileBuffer) {
PsiFile psiFile = psiElement.getContainingFile();
boolean mayHaveClassesInside = false;
if (psiFile instanceof PsiJavaFileImpl) {
Lexer originalLexer = JavaParserDefinition.createLexer(((PsiJavaFileImpl)psiFile).getLanguageLevel());
FilterLexer lexer = new FilterLexer(originalLexer, new FilterLexer.SetFilter(StdTokenSets.WHITE_SPACE_OR_COMMENT_BIT_SET));
final TextRange range = psiElement.getTextRange();
lexer.start(fileBuffer, range.getStartOffset(), range.getEndOffset());
boolean isInNewExpression = false;
boolean isRightAfterNewExpression = false;
int angleLevel = 0;
int parenLevel = 0;
do {
IElementType tokenType = lexer.getTokenType();
if (tokenType == null) break;
if (tokenType == JavaTokenType.NEW_KEYWORD) {
isInNewExpression = true;
}
else if (tokenType == JavaTokenType.LPARENTH) {
if (isInNewExpression) parenLevel++;
}
else if (tokenType == JavaTokenType.LT) {
if (isInNewExpression) angleLevel++;
}
else if (tokenType == JavaTokenType.GT) {
if (isInNewExpression) angleLevel--;
}
else if (tokenType == JavaTokenType.RPARENTH) {
if (isInNewExpression) {
parenLevel--;
if (parenLevel == 0) {
isRightAfterNewExpression = true;
}
}
}
else if (tokenType == JavaTokenType.LBRACE) {
if (isInNewExpression || isRightAfterNewExpression) {
mayHaveClassesInside = true;
}
}
else if (tokenType == JavaTokenType.LBRACKET) {
if (parenLevel == 0 && angleLevel == 0) isInNewExpression = false;
}
else if (tokenType == JavaTokenType.INTERFACE_KEYWORD || tokenType == JavaTokenType.CLASS_KEYWORD ||
tokenType == JavaTokenType.ENUM_KEYWORD) {
mayHaveClassesInside = true;
}
if (isInNewExpression && isRightAfterNewExpression) {
isInNewExpression = false;
}
else {
isRightAfterNewExpression = false;
}
lexer.advance();
}
while (!mayHaveClassesInside);
}
return mayHaveClassesInside;
}
}