From 0a2bea5ec2d0fbcec136d307df59678205fa23f8 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Tue, 21 Feb 2012 19:33:45 +0400 Subject: [PATCH] removed redundant or outdated modules --- .idea/copyright/profiles_settings.xml | 6 +- idea_fix/idea_fix.iml | 21 - .../intellij/core/CoreJavaFileManager.java | 170 -- .../intellij/lang/impl/PsiBuilderImpl.java | 1629 ----------------- .../openapi/editor/impl/CharArray.java | 668 ------- .../openapi/fileEditor/impl/LoadTextUtil.java | 418 ----- .../com/intellij/openapi/util/IconLoader.java | 351 ---- .../openapi/util/UserDataHolderBase.java | 265 --- .../openapi/vfs/impl/jar/CoreJarHandler.java | 54 - .../openapi/vfs/impl/jar/JarHandlerBase.java | 266 --- .../openapi/vfs/impl/jar/VirtualJarFile.java | 117 -- .../persistent/PersistentFSConstants.java | 39 - .../psi/SingleRootFileViewProvider.java | 535 ------ .../com/intellij/psi/text/BlockSupport.java | 77 - .../src/com/intellij/util/ReflectionUtil.java | 288 --- jetTests/test/ExampleTestSuite.java | 33 - 16 files changed, 4 insertions(+), 4933 deletions(-) delete mode 100644 idea_fix/idea_fix.iml delete mode 100644 idea_fix/src/com/intellij/core/CoreJavaFileManager.java delete mode 100644 idea_fix/src/com/intellij/lang/impl/PsiBuilderImpl.java delete mode 100644 idea_fix/src/com/intellij/openapi/editor/impl/CharArray.java delete mode 100644 idea_fix/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java delete mode 100644 idea_fix/src/com/intellij/openapi/util/IconLoader.java delete mode 100644 idea_fix/src/com/intellij/openapi/util/UserDataHolderBase.java delete mode 100644 idea_fix/src/com/intellij/openapi/vfs/impl/jar/CoreJarHandler.java delete mode 100644 idea_fix/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java delete mode 100644 idea_fix/src/com/intellij/openapi/vfs/impl/jar/VirtualJarFile.java delete mode 100644 idea_fix/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConstants.java delete mode 100644 idea_fix/src/com/intellij/psi/SingleRootFileViewProvider.java delete mode 100644 idea_fix/src/com/intellij/psi/text/BlockSupport.java delete mode 100644 idea_fix/src/com/intellij/util/ReflectionUtil.java delete mode 100644 jetTests/test/ExampleTestSuite.java diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml index 3572571ad83..ace2e994924 100644 --- a/.idea/copyright/profiles_settings.xml +++ b/.idea/copyright/profiles_settings.xml @@ -1,5 +1,7 @@ - - + + + + \ No newline at end of file diff --git a/idea_fix/idea_fix.iml b/idea_fix/idea_fix.iml deleted file mode 100644 index 3fd75b7321c..00000000000 --- a/idea_fix/idea_fix.iml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/idea_fix/src/com/intellij/core/CoreJavaFileManager.java b/idea_fix/src/com/intellij/core/CoreJavaFileManager.java deleted file mode 100644 index c415fba3b91..00000000000 --- a/idea_fix/src/com/intellij/core/CoreJavaFileManager.java +++ /dev/null @@ -1,170 +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.core; - -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem; -import com.intellij.openapi.vfs.local.CoreLocalFileSystem; -import com.intellij.psi.*; -import com.intellij.psi.impl.file.PsiPackageImpl; -import com.intellij.psi.impl.file.impl.JavaFileManager; -import com.intellij.psi.search.GlobalSearchScope; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * @author yole - */ -public class CoreJavaFileManager implements JavaFileManager { - private final CoreLocalFileSystem myLocalFileSystem; - private final CoreJarFileSystem myJarFileSystem; - private final List myClasspath = new ArrayList(); - private final List myVirtualClasspath = new ArrayList(); - private final PsiManager myPsiManager; - - public CoreJavaFileManager(PsiManager psiManager, CoreLocalFileSystem localFileSystem, CoreJarFileSystem jarFileSystem) { - myPsiManager = psiManager; - myLocalFileSystem = localFileSystem; - myJarFileSystem = jarFileSystem; - addToClasspath("rt.jar"); - } - - @Override - public PsiPackage findPackage(@NotNull String packageName) { - String dirName = packageName.replace(".", "/"); - for (File file : myClasspath) { - VirtualFile classDir = findUnderClasspathEntry(file, dirName); - if (classDir != null) { - return new PsiPackageImpl(myPsiManager, packageName); - } - } - - for (String str : myVirtualClasspath) { - VirtualFile file = myJarFileSystem.findFileByPath(str + "!/" + dirName); - if (file != null) { - return new PsiPackageImpl(myPsiManager, packageName); - } - } - return null; - } - - @Nullable - private VirtualFile findUnderClasspathEntry(File classpathEntry, String relativeName) { - if (classpathEntry.isFile()) { - return myJarFileSystem.findFileByPath(classpathEntry.getPath() + "!/" + relativeName); - } else { - return myLocalFileSystem.findFileByPath(new File(classpathEntry, relativeName).getPath()); - } - } - - @Nullable - private PsiClass findInVirtualJar(String classpathEntry, String relativeName) { - String fileName = relativeName.replace(".", "/") + ".class"; - VirtualFile file = myJarFileSystem.findFileByPath(classpathEntry + "!/" + fileName); - if (file != null) { - PsiFile psiFile = myPsiManager.findFile(file); - if (!(psiFile instanceof PsiJavaFile)) { - /*ErrorWriter.ERROR_WRITER.writeException(ErrorWriter.getExceptionForLog( - "UNKNOWN", new UnsupportedOperationException("no java file for .class"), classpathEntry + "!/" + relativeName - )); - return null;*/ - throw new UnsupportedOperationException("no java file for .class " + classpathEntry + "!/" + relativeName); - } - final PsiClass[] classes = ((PsiJavaFile) psiFile).getClasses(); - if (classes.length == 1) { - return classes[0]; - } - } - return null; - } - - @Override - public PsiClass findClass(@NotNull String qName, @NotNull GlobalSearchScope scope) { - for (File file : myClasspath) { - final PsiClass psiClass = findClassInClasspathEntry(qName, file); - if (psiClass != null) { - return psiClass; - } - } - for (String str : myVirtualClasspath) { - final PsiClass psiClass = findInVirtualJar(str, qName); - if (psiClass != null) { - return psiClass; - } - } - return null; - } - - @Nullable - private PsiClass findClassInClasspathEntry(String qName, File file) { - String fileName = qName.replace(".", "/") + ".class"; - VirtualFile classFile = findUnderClasspathEntry(file, fileName); - - if (classFile != null) { - PsiFile psiFile = myPsiManager.findFile(classFile); - if (!(psiFile instanceof PsiJavaFile)) { - throw new UnsupportedOperationException("no java file for .class"); - } - final PsiClass[] classes = ((PsiJavaFile) psiFile).getClasses(); - if (classes.length == 1) { - return classes[0]; - } - } - return null; - } - - @Override - public PsiClass[] findClasses(@NotNull String qName, @NotNull GlobalSearchScope scope) { - List result = new ArrayList(); - for (File file : myClasspath) { - final PsiClass psiClass = findClassInClasspathEntry(qName, file); - if (psiClass != null) { - result.add(psiClass); - } - } - for (String str : myVirtualClasspath) { - final PsiClass psiClass = findInVirtualJar(str, qName); - if (psiClass != null) { - result.add(psiClass); - } - } - return result.toArray(new PsiClass[result.size()]); - } - - @Override - public Collection getNonTrivialPackagePrefixes() { - return Collections.emptyList(); - } - - @Override - public void initialize() { - } - - public void addToClasspath(File path) { - myClasspath.add(path); - } - - public void addToClasspath(String path) { - myVirtualClasspath.add(path); - } - -} diff --git a/idea_fix/src/com/intellij/lang/impl/PsiBuilderImpl.java b/idea_fix/src/com/intellij/lang/impl/PsiBuilderImpl.java deleted file mode 100644 index e4f84e71c51..00000000000 --- a/idea_fix/src/com/intellij/lang/impl/PsiBuilderImpl.java +++ /dev/null @@ -1,1629 +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.lang.impl; - -import com.intellij.lang.*; -import com.intellij.lexer.Lexer; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressIndicatorProvider; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.psi.PsiErrorElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.TokenType; -import com.intellij.psi.impl.source.CharTableImpl; -import com.intellij.psi.impl.source.resolve.FileContextUtil; -import com.intellij.psi.impl.source.text.BlockSupportImpl; -import com.intellij.psi.impl.source.text.DiffLog; -import com.intellij.psi.impl.source.tree.*; -import com.intellij.psi.text.BlockSupport; -import com.intellij.psi.tree.*; -import com.intellij.util.CharTable; -import com.intellij.util.ThreeState; -import com.intellij.util.TripleFunction; -import com.intellij.util.containers.CollectionFactory; -import com.intellij.util.containers.Convertor; -import com.intellij.util.containers.LimitedPool; -import com.intellij.util.containers.Stack; -import com.intellij.util.diff.DiffTreeChangeBuilder; -import com.intellij.util.diff.FlyweightCapableTreeStructure; -import com.intellij.util.diff.ShallowNodeComparator; -import com.intellij.util.text.CharArrayUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * @author max - */ -public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, ASTNodeBuilder { - private static final Logger LOG = Logger.getInstance("#com.intellij.lang.impl.PsiBuilderImpl"); - - // function stored in PsiBuilderImpl' user data which called during reparse when merge algorithm is not sure what to merge - public static final Key, ThreeState>> - CUSTOM_COMPARATOR = Key.create("CUSTOM_COMPARATOR"); - - private final Project myProject; - private PsiFile myFile; - - private int[] myLexStarts; - private IElementType[] myLexTypes; - private int myCurrentLexeme; - - private final MyList myProduction = new MyList(); - - private final Lexer myLexer; - private final TokenSet myWhitespaces; - private TokenSet myComments; - - private CharTable myCharTable; - private final CharSequence myText; - private final char[] myTextArray; - private boolean myDebugMode = false; - private int myLexemeCount = 0; - private boolean myTokenTypeChecked; - private ITokenTypeRemapper myRemapper; - private WhitespaceSkippedCallback myWhitespaceSkippedCallback; - - private final ASTNode myOriginalTree; - private final MyTreeStructure myParentLightTree; - - private static TokenSet ourAnyLanguageWhitespaceTokens = TokenSet.EMPTY; - - private Map myUserData = null; - - private final LimitedPool START_MARKERS = new LimitedPool(2000, new LimitedPool.ObjectFactory() { - @Override - public StartMarker create() { - return new StartMarker(); - } - - @Override - public void cleanup(final StartMarker startMarker) { - startMarker.clean(); - } - }); - - private final LimitedPool DONE_MARKERS = new LimitedPool(2000, new LimitedPool.ObjectFactory() { - @Override - public DoneMarker create() { - return new DoneMarker(); - } - - @Override - public void cleanup(final DoneMarker doneMarker) { - doneMarker.clean(); - } - }); - - private static final WhitespacesAndCommentsBinder DEFAULT_LEFT_EDGE_TOKEN_BINDER = new WhitespacesAndCommentsBinder() { - @Override - public int getEdgePosition(final List tokens, final boolean atStreamEdge, final TokenTextGetter getter) { - return tokens.size(); - } - }; - - private static final WhitespacesAndCommentsBinder DEFAULT_RIGHT_EDGE_TOKEN_BINDER = new WhitespacesAndCommentsBinder() { - @Override - public int getEdgePosition(final List tokens, final boolean atStreamEdge, final TokenTextGetter getter) { - return 0; - } - }; - - public static void registerWhitespaceToken(IElementType type) { - ourAnyLanguageWhitespaceTokens = TokenSet.orSet(ourAnyLanguageWhitespaceTokens, TokenSet.create(type)); - } - - public PsiBuilderImpl(@NotNull Project project, - PsiFile containingFile, - @NotNull ParserDefinition parserDefinition, - @NotNull Lexer lexer, - CharTable charTable, - @NotNull final CharSequence text, - @Nullable ASTNode originalTree, - @Nullable MyTreeStructure parentLightTree) { - this(project, containingFile, parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer, charTable, text, - originalTree, parentLightTree); - } - - public PsiBuilderImpl(Project project, - PsiFile containingFile, - @NotNull TokenSet whiteSpaces, - @NotNull TokenSet comments, - @NotNull Lexer lexer, - CharTable charTable, - @NotNull final CharSequence text, - @Nullable ASTNode originalTree, - @Nullable MyTreeStructure parentLightTree) { - myProject = project; - myFile = containingFile; - - myText = text; - myTextArray = CharArrayUtil.fromSequenceWithoutCopying(text); - myLexer = lexer; - - myWhitespaces = whiteSpaces; - myComments = comments; - myCharTable = charTable; - myOriginalTree = originalTree; - myParentLightTree = parentLightTree; - - cacheLexemes(); - } - - public PsiBuilderImpl(@NotNull final Project project, - @NotNull final ParserDefinition parserDefinition, - @NotNull final Lexer lexer, - @NotNull final ASTNode chameleon, - @NotNull final CharSequence text) { - this(project, SharedImplUtil.getContainingFile(chameleon), parserDefinition, lexer, SharedImplUtil.findCharTableByTree(chameleon), text, - chameleon.getUserData(BlockSupport.TREE_TO_BE_REPARSED), null); - } - - public PsiBuilderImpl(@NotNull final Project project, - @NotNull final ParserDefinition parserDefinition, - @NotNull final Lexer lexer, - @NotNull final LighterLazyParseableNode chameleon, - @NotNull final CharSequence text) { - this(project, chameleon.getContainingFile(), parserDefinition, lexer, chameleon.getCharTable(), text, - null, ((LazyParseableToken) chameleon).myParent); - } - - private void cacheLexemes() { - int approxLexCount = Math.max(10, myText.length() / 5); - - myLexStarts = new int[approxLexCount]; - myLexTypes = new IElementType[approxLexCount]; - - myLexer.start(myText); - int i = 0; - int offset = 0; - while (true) { - ProgressIndicatorProvider.checkCanceled(); - IElementType type = myLexer.getTokenType(); - if (type == null) break; - - if (i >= myLexTypes.length - 1) { - resizeLexemes(i * 3 / 2); - } - int tokenStart = myLexer.getTokenStart(); - if (tokenStart < offset) { - final StringBuilder sb = new StringBuilder(); - final IElementType tokenType = myLexer.getTokenType(); - sb.append("Token sequence broken") - .append("\n this: '").append(myLexer.getTokenText()).append("' (").append(tokenType).append(':') - .append(tokenType != null ? tokenType.getLanguage() : null).append(") ").append(tokenStart).append(":").append(myLexer.getTokenEnd()); - if (i > 0) { - final int prevStart = myLexStarts[i - 1]; - sb.append("\n prev: '").append(myText.subSequence(prevStart, offset)).append("' (").append(myLexTypes[i - 1]).append(':') - .append(myLexTypes[i - 1].getLanguage()).append(") ").append(prevStart).append(":").append(offset); - } - final int quoteStart = Math.max(tokenStart - 256, 0); - final int quoteEnd = Math.min(tokenStart + 256, myText.length()); - sb.append("\n quote: [").append(quoteStart).append(':').append(quoteEnd) - .append("] '").append(myText.subSequence(quoteStart, quoteEnd)).append('\''); - LOG.error(sb); - } - myLexStarts[i] = offset = tokenStart; - myLexTypes[i] = type; - i++; - myLexer.advance(); - } - - myLexStarts[i] = myText.length(); - - myLexemeCount = i; - } - - @Override - public Project getProject() { - return myProject; - } - - @Override - public void enforceCommentTokens(TokenSet tokens) { - myComments = tokens; - } - - @Override - @Nullable - public LighterASTNode getLatestDoneMarker() { - int index = myProduction.size() - 1; - while (index >= 0) { - ProductionMarker marker = myProduction.get(index); - if (marker instanceof DoneMarker) return ((DoneMarker) marker).myStart; - --index; - } - return null; - } - - private abstract static class Node implements LighterASTNode { - public abstract int hc(); - } - - @Override - public IElementType getElementType(int lexemIndex) { - return lexemIndex < myLexemeCount && lexemIndex >= 0 ? myLexTypes[lexemIndex] : null; - } - - public abstract static class ProductionMarker extends Node { - protected int myLexemeIndex; - protected WhitespacesAndCommentsBinder myEdgeTokenBinder; - protected ProductionMarker myParent; - protected ProductionMarker myNext; - - public void clean() { - myLexemeIndex = 0; - myParent = myNext = null; - } - } - - private static class StartMarker extends ProductionMarker implements Marker { - private PsiBuilderImpl myBuilder; - private IElementType myType; - private DoneMarker myDoneMarker; - private Throwable myDebugAllocationPosition; - private ProductionMarker myFirstChild; - private ProductionMarker myLastChild; - private int myHC = -1; - - private StartMarker() { - myEdgeTokenBinder = DEFAULT_LEFT_EDGE_TOKEN_BINDER; - } - - @Override - public void clean() { - super.clean(); - myBuilder = null; - myType = null; - myDoneMarker = null; - myDebugAllocationPosition = null; - myFirstChild = myLastChild = null; - myHC = -1; - myEdgeTokenBinder = DEFAULT_LEFT_EDGE_TOKEN_BINDER; - } - - @Override - public int hc() { - if (myHC == -1) { - PsiBuilderImpl builder = myBuilder; - int hc = 0; - final CharSequence buf = builder.myText; - final char[] bufArray = builder.myTextArray; - ProductionMarker child = myFirstChild; - int lexIdx = myLexemeIndex; - - while (child != null) { - int lastLeaf = child.myLexemeIndex; - for (int i = builder.myLexStarts[lexIdx]; i < builder.myLexStarts[lastLeaf]; i++) { - hc += bufArray != null ? bufArray[i] : buf.charAt(i); - } - lexIdx = lastLeaf; - hc += child.hc(); - if (child instanceof StartMarker) { - lexIdx = ((StartMarker) child).myDoneMarker.myLexemeIndex; - } - child = child.myNext; - } - - for (int i = builder.myLexStarts[lexIdx]; i < builder.myLexStarts[myDoneMarker.myLexemeIndex]; i++) { - hc += bufArray != null ? bufArray[i] : buf.charAt(i); - } - - myHC = hc; - } - - return myHC; - } - - @Override - public int getStartOffset() { - return myBuilder.myLexStarts[myLexemeIndex]; - } - - @Override - public int getEndOffset() { - return myBuilder.myLexStarts[myDoneMarker.myLexemeIndex]; - } - - public void addChild(ProductionMarker node) { - if (myFirstChild == null) { - myFirstChild = node; - myLastChild = node; - } else { - myLastChild.myNext = node; - myLastChild = node; - } - } - - @Override - public Marker precede() { - return myBuilder.precede(this); - } - - @Override - public void drop() { - myBuilder.drop(this); - } - - @Override - public void rollbackTo() { - myBuilder.rollbackTo(this); - } - - @Override - public void done(IElementType type) { - myType = type; - myBuilder.done(this); - } - - @Override - public void collapse(IElementType type) { - myType = type; - myBuilder.collapse(this); - } - - @Override - public void doneBefore(IElementType type, Marker before) { - myType = type; - myBuilder.doneBefore(this, before); - } - - @Override - public void doneBefore(final IElementType type, final Marker before, final String errorMessage) { - final StartMarker marker = (StartMarker) before; - myBuilder.myProduction.add(myBuilder.myProduction.lastIndexOf(marker), - new ErrorItem(myBuilder, errorMessage, marker.myLexemeIndex)); - doneBefore(type, before); - } - - @Override - public void error(String message) { - myType = TokenType.ERROR_ELEMENT; - myBuilder.error(this, message); - } - - @Override - public void errorBefore(final String message, final Marker before) { - myType = TokenType.ERROR_ELEMENT; - myBuilder.errorBefore(this, message, before); - } - - @Override - public IElementType getTokenType() { - return myType; - } - - @Override - public void setCustomEdgeTokenBinders(final WhitespacesAndCommentsBinder left, final WhitespacesAndCommentsBinder right) { - if (left != null) { - myEdgeTokenBinder = left; - } - - if (right != null) { - if (myDoneMarker == null) - throw new IllegalArgumentException("Cannot set right-edge processor for unclosed marker"); - myDoneMarker.myEdgeTokenBinder = right; - } - } - } - - private Marker precede(final StartMarker marker) { - int idx = myProduction.lastIndexOf(marker); - if (idx < 0) { - LOG.error("Cannot precede dropped or rolled-back marker"); - } - StartMarker pre = createMarker(marker.myLexemeIndex); - myProduction.add(idx, pre); - return pre; - } - - private abstract static class Token extends Node { - protected PsiBuilderImpl myBuilder; - private IElementType myTokenType; - private int myTokenStart; - private int myTokenEnd; - private int myHC = -1; - - public void clean() { - myBuilder = null; - myHC = -1; - } - - @Override - public int hc() { - if (myHC == -1) { - int hc = 0; - if (myTokenType instanceof TokenWrapper) { - final String value = ((TokenWrapper) myTokenType).getValue(); - for (int i = 0; i < value.length(); i++) { - hc += value.charAt(i); - } - } else { - final int start = myTokenStart; - final int end = myTokenEnd; - final CharSequence buf = myBuilder.myText; - final char[] bufArray = myBuilder.myTextArray; - - for (int i = start; i < end; i++) { - hc += bufArray != null ? bufArray[i] : buf.charAt(i); - } - } - - myHC = hc; - } - - return myHC; - } - - @Override - public int getEndOffset() { - return myTokenEnd; - } - - @Override - public int getStartOffset() { - return myTokenStart; - } - - public CharSequence getText() { - if (myTokenType instanceof TokenWrapper) { - return ((TokenWrapper) myTokenType).getValue(); - } - - return myBuilder.myText.subSequence(myTokenStart, myTokenEnd); - } - - @Override - public IElementType getTokenType() { - return myTokenType; - } - } - - private static class TokenNode extends Token implements LighterASTTokenNode { - } - - private static class LazyParseableToken extends Token implements LighterLazyParseableNode, ASTUnparsedNodeMarker { - private MyTreeStructure myParent; - private FlyweightCapableTreeStructure myParsed; - private int myStartIndex; - private int myEndIndex; - - @Override - public void clean() { - super.clean(); - myParent = null; - myParsed = null; - } - - @Override - public PsiFile getContainingFile() { - return myBuilder.myFile; - } - - @Override - public CharTable getCharTable() { - return myBuilder.myCharTable; - } - - public FlyweightCapableTreeStructure parseContents() { - if (myParsed == null) { - myParsed = ((ILightLazyParseableElementType) getTokenType()).parseContents(this); - } - return myParsed; - } - - public ASTNodeBuilder getBuilder() { - return myBuilder; - } - - @Override - public int getStartLexemIndex() { - return myStartIndex; - } - - @Override - public int getEndLexemIndex() { - return myEndIndex; - } - - } - - private static class DoneMarker extends ProductionMarker { - private StartMarker myStart; - private boolean myCollapse = false; - - public DoneMarker() { - myEdgeTokenBinder = DEFAULT_RIGHT_EDGE_TOKEN_BINDER; - } - - public DoneMarker(final StartMarker marker, final int currentLexeme) { - this(); - myLexemeIndex = currentLexeme; - myStart = marker; - } - - @Override - public void clean() { - super.clean(); - myStart = null; - myEdgeTokenBinder = DEFAULT_RIGHT_EDGE_TOKEN_BINDER; - } - - @Override - public int hc() { - throw new UnsupportedOperationException("Shall not be called on this kind of markers"); - } - - @Override - public IElementType getTokenType() { - throw new UnsupportedOperationException("Shall not be called on this kind of markers"); - } - - @Override - public int getEndOffset() { - throw new UnsupportedOperationException("Shall not be called on this kind of markers"); - } - - @Override - public int getStartOffset() { - throw new UnsupportedOperationException("Shall not be called on this kind of markers"); - } - } - - private static class DoneWithErrorMarker extends DoneMarker { - private String myMessage; - - public DoneWithErrorMarker(final StartMarker marker, final int currentLexeme, final String message) { - super(marker, currentLexeme); - myMessage = message; - } - - @Override - public void clean() { - super.clean(); - myMessage = null; - } - } - - private static class ErrorItem extends ProductionMarker { - private final PsiBuilderImpl myBuilder; - private String myMessage; - - public ErrorItem(final PsiBuilderImpl builder, final String message, final int idx) { - myBuilder = builder; - myMessage = message; - myLexemeIndex = idx; - myEdgeTokenBinder = DEFAULT_RIGHT_EDGE_TOKEN_BINDER; - } - - @Override - public void clean() { - super.clean(); - myMessage = null; - } - - @Override - public int hc() { - return 0; - } - - @Override - public int getEndOffset() { - return myBuilder.myLexStarts[myLexemeIndex]; - } - - @Override - public int getStartOffset() { - return myBuilder.myLexStarts[myLexemeIndex]; - } - - @Override - public IElementType getTokenType() { - return TokenType.ERROR_ELEMENT; - } - } - - @Override - public CharSequence getOriginalText() { - return myText; - } - - @Override - public IElementType getTokenType() { - if (eof()) return null; - - if (myRemapper != null) { - IElementType type = myLexTypes[myCurrentLexeme]; - type = myRemapper.filter(type, myLexStarts[myCurrentLexeme], myLexStarts[myCurrentLexeme + 1], myLexer.getBufferSequence()); - myLexTypes[myCurrentLexeme] = type; // filter may have changed the type - return type; - } - return myLexTypes[myCurrentLexeme]; - } - - @Override - public void setTokenTypeRemapper(final ITokenTypeRemapper remapper) { - myRemapper = remapper; - } - - @Override - public void remapCurrentToken(IElementType type) { - myLexTypes[myCurrentLexeme] = type; - } - - @Nullable - @Override - public IElementType lookAhead(int steps) { - if (eof()) { // ensure we skip over whitespace if it's needed - return null; - } - int cur = myCurrentLexeme; - - while (steps > 0) { - ++cur; - while (cur < myLexemeCount && whitespaceOrComment(myLexTypes[cur])) { - cur++; - } - - steps--; - } - - return cur < myLexemeCount ? myLexTypes[cur] : null; - } - - @Override - public IElementType rawLookup(int steps) { - int cur = myCurrentLexeme + steps; - return cur < myLexemeCount && cur >= 0 ? myLexTypes[cur] : null; - } - - @Override - public int rawTokenTypeStart(int steps) { - int cur = myCurrentLexeme + steps; - if (cur < 0) return -1; - if (cur >= myLexemeCount) return getOriginalText().length(); - return myLexStarts[cur]; - } - - @Override - public void setWhitespaceSkippedCallback(WhitespaceSkippedCallback callback) { - myWhitespaceSkippedCallback = callback; - } - - @Override - public void advanceLexer() { - if (eof()) return; - - if (!myTokenTypeChecked) { - LOG.assertTrue(eof(), "Probably a bug: eating token without its type checking"); - } - myTokenTypeChecked = false; - myCurrentLexeme++; - ProgressIndicatorProvider.checkCanceled(); - } - - private void skipWhitespace() { - while (myCurrentLexeme < myLexemeCount && whitespaceOrComment(myLexTypes[myCurrentLexeme])) { - onSkip(myLexTypes[myCurrentLexeme], myLexStarts[myCurrentLexeme], myCurrentLexeme + 1 < myLexemeCount ? myLexStarts[myCurrentLexeme + 1] : myText.length()); - myCurrentLexeme++; - } - } - - private void onSkip(IElementType type, int start, int end) { - if (myWhitespaceSkippedCallback != null) { - myWhitespaceSkippedCallback.onSkip(type, start, end); - } - } - - @Override - public int getCurrentOffset() { - if (eof()) return getOriginalText().length(); - return myLexStarts[myCurrentLexeme]; - } - - @Override - @Nullable - public String getTokenText() { - if (eof()) return null; - final IElementType type = getTokenType(); - if (type instanceof TokenWrapper) { - return ((TokenWrapper) type).getValue(); - } - return myText.subSequence(myLexStarts[myCurrentLexeme], myLexStarts[myCurrentLexeme + 1]).toString(); - } - - private void resizeLexemes(final int newSize) { - int count = Math.min(newSize, myLexTypes.length); - int[] newStarts = new int[newSize + 1]; - System.arraycopy(myLexStarts, 0, newStarts, 0, count); - myLexStarts = newStarts; - - IElementType[] newTypes = new IElementType[newSize]; - System.arraycopy(myLexTypes, 0, newTypes, 0, count); - myLexTypes = newTypes; - } - - private boolean whitespaceOrComment(IElementType token) { - return myWhitespaces.contains(token) || myComments.contains(token); - } - - @Override - public Marker mark() { - if (!myProduction.isEmpty()) { - skipWhitespace(); - } - StartMarker marker = createMarker(myCurrentLexeme); - - myProduction.add(marker); - return marker; - } - - private StartMarker createMarker(final int lexemeIndex) { - StartMarker marker = START_MARKERS.alloc(); - marker.myLexemeIndex = lexemeIndex; - marker.myBuilder = this; - - if (myDebugMode) { - marker.myDebugAllocationPosition = new Throwable("Created at the following trace."); - } - return marker; - } - - @Override - public final boolean eof() { - if (!markTokenTypeChecked()) { - skipWhitespace(); - } - return myCurrentLexeme >= myLexemeCount; - } - - public boolean markTokenTypeChecked() { - if (!myTokenTypeChecked) { - myTokenTypeChecked = true; - return false; - } - return true; - } - - @SuppressWarnings({"SuspiciousMethodCalls"}) - private void rollbackTo(Marker marker) { - myCurrentLexeme = ((StartMarker) marker).myLexemeIndex; - markTokenTypeChecked(); - int idx = myProduction.lastIndexOf(marker); - if (idx < 0) { - LOG.error("The marker must be added before rolled back to."); - } - myProduction.removeRange(idx, myProduction.size()); - START_MARKERS.recycle((StartMarker) marker); - } - - @SuppressWarnings({"SuspiciousMethodCalls"}) - public void drop(Marker marker) { - final DoneMarker doneMarker = ((StartMarker) marker).myDoneMarker; - if (doneMarker != null) { - myProduction.remove(myProduction.lastIndexOf(doneMarker)); - DONE_MARKERS.recycle(doneMarker); - } - final boolean removed = myProduction.remove(myProduction.lastIndexOf(marker)) == marker; - if (!removed) { - LOG.error("The marker must be added before it is dropped."); - } - START_MARKERS.recycle((StartMarker) marker); - } - - public void error(Marker marker, String message) { - doValidityChecks(marker, null); - - DoneWithErrorMarker doneMarker = new DoneWithErrorMarker((StartMarker) marker, myCurrentLexeme, message); - boolean tieToTheLeft = isEmpty(((StartMarker) marker).myLexemeIndex, myCurrentLexeme); - if (tieToTheLeft) ((StartMarker) marker).myEdgeTokenBinder = DEFAULT_RIGHT_EDGE_TOKEN_BINDER; - - ((StartMarker) marker).myDoneMarker = doneMarker; - myProduction.add(doneMarker); - } - - @SuppressWarnings({"SuspiciousMethodCalls"}) - public void errorBefore(Marker marker, String message, Marker before) { - doValidityChecks(marker, before); - - int beforeIndex = myProduction.lastIndexOf(before); - - DoneWithErrorMarker doneMarker = new DoneWithErrorMarker((StartMarker) marker, ((StartMarker) before).myLexemeIndex, message); - boolean tieToTheLeft = isEmpty(((StartMarker) marker).myLexemeIndex, ((StartMarker) before).myLexemeIndex); - if (tieToTheLeft) ((StartMarker) marker).myEdgeTokenBinder = DEFAULT_RIGHT_EDGE_TOKEN_BINDER; - - ((StartMarker) marker).myDoneMarker = doneMarker; - myProduction.add(beforeIndex, doneMarker); - } - - public void done(final Marker marker) { - doValidityChecks(marker, null); - - DoneMarker doneMarker = DONE_MARKERS.alloc(); - doneMarker.myStart = (StartMarker) marker; - doneMarker.myLexemeIndex = myCurrentLexeme; - boolean tieToTheLeft = doneMarker.myStart.myType.isLeftBound() && - isEmpty(((StartMarker) marker).myLexemeIndex, myCurrentLexeme); - if (tieToTheLeft) ((StartMarker) marker).myEdgeTokenBinder = DEFAULT_RIGHT_EDGE_TOKEN_BINDER; - - ((StartMarker) marker).myDoneMarker = doneMarker; - myProduction.add(doneMarker); - } - - @SuppressWarnings({"SuspiciousMethodCalls"}) - public void doneBefore(Marker marker, Marker before) { - doValidityChecks(marker, before); - - int beforeIndex = myProduction.lastIndexOf(before); - - DoneMarker doneMarker = DONE_MARKERS.alloc(); - doneMarker.myLexemeIndex = ((StartMarker) before).myLexemeIndex; - doneMarker.myStart = (StartMarker) marker; - boolean tieToTheLeft = doneMarker.myStart.myType.isLeftBound() && - isEmpty(((StartMarker) marker).myLexemeIndex, ((StartMarker) before).myLexemeIndex); - if (tieToTheLeft) ((StartMarker) marker).myEdgeTokenBinder = DEFAULT_RIGHT_EDGE_TOKEN_BINDER; - - ((StartMarker) marker).myDoneMarker = doneMarker; - myProduction.add(beforeIndex, doneMarker); - } - - private boolean isEmpty(final int startIdx, final int endIdx) { - for (int i = startIdx; i < endIdx; i++) { - final IElementType token = myLexTypes[i]; - if (!whitespaceOrComment(token)) return false; - } - return true; - } - - public void collapse(final Marker marker) { - done(marker); - ((StartMarker) marker).myDoneMarker.myCollapse = true; - } - - @SuppressWarnings({"UseOfSystemOutOrSystemErr", "SuspiciousMethodCalls"}) - private void doValidityChecks(final Marker marker, @Nullable final Marker before) { - final DoneMarker doneMarker = ((StartMarker) marker).myDoneMarker; - if (doneMarker != null) { - LOG.error("Marker already done."); - } - - if (!myDebugMode) return; - - int idx = myProduction.lastIndexOf(marker); - if (idx < 0) { - LOG.error("Marker has never been added."); - } - - int endIdx = myProduction.size(); - if (before != null) { - endIdx = myProduction.lastIndexOf(before); - if (endIdx < 0) { - LOG.error("'Before' marker has never been added."); - } - if (idx > endIdx) { - LOG.error("'Before' marker precedes this one."); - } - } - - for (int i = endIdx - 1; i > idx; i--) { - Object item = myProduction.get(i); - if (item instanceof StartMarker) { - StartMarker otherMarker = (StartMarker) item; - if (otherMarker.myDoneMarker == null) { - final Throwable debugAllocOther = otherMarker.myDebugAllocationPosition; - final Throwable debugAllocThis = ((StartMarker) marker).myDebugAllocationPosition; - if (debugAllocOther != null) { - debugAllocThis.printStackTrace(System.err); - debugAllocOther.printStackTrace(System.err); - } - LOG.error("Another not done marker added after this one. Must be done before this."); - } - } - } - } - - @Override - public void error(String messageText) { - final ProductionMarker lastMarker = myProduction.get(myProduction.size() - 1); - if (lastMarker instanceof ErrorItem && lastMarker.myLexemeIndex == myCurrentLexeme) { - return; - } - myProduction.add(new ErrorItem(this, messageText, myCurrentLexeme)); - } - - @Override - public ASTNode getTreeBuilt() { - try { - return buildTree(); - } finally { - for (int i = 0, myProductionSize = myProduction.size(); i < myProductionSize; i++) { - ProductionMarker marker = myProduction.get(i); - if (marker instanceof StartMarker) { - START_MARKERS.recycle((StartMarker) marker); - } else if (marker instanceof DoneMarker) { - DONE_MARKERS.recycle((DoneMarker) marker); - } - } - } - } - - private ASTNode buildTree() { - final StartMarker rootMarker = prepareLightTree(); - final boolean isTooDeep = myFile != null && BlockSupport.isTooDeep(myFile.getOriginalFile()); - - if (myOriginalTree != null && !isTooDeep) { - DiffLog diffLog = merge(myOriginalTree, rootMarker); - throw new BlockSupport.ReparsedSuccessfullyException(diffLog); - } - - final ASTNode rootNode = createRootAST(rootMarker); - bind(rootMarker, (CompositeElement) rootNode); - - if (isTooDeep && !(rootNode instanceof FileElement)) { - final ASTNode childNode = rootNode.getFirstChildNode(); - childNode.putUserData(BlockSupport.TREE_DEPTH_LIMIT_EXCEEDED, Boolean.TRUE); - } - - return rootNode; - } - - @Override - public FlyweightCapableTreeStructure getLightTree() { - final StartMarker rootMarker = prepareLightTree(); - return new MyTreeStructure(rootMarker, myParentLightTree); - } - - private ASTNode createRootAST(final StartMarker rootMarker) { - final IElementType type = rootMarker.getTokenType(); - final ASTNode rootNode = type instanceof ILazyParseableElementType ? - ASTFactory.lazy((ILazyParseableElementType) type, null) : createComposite(rootMarker); - if (myCharTable == null) { - myCharTable = rootNode instanceof FileElement ? ((FileElement) rootNode).getCharTable() : new CharTableImpl(); - } - if (!(rootNode instanceof FileElement)) { - rootNode.putUserData(CharTable.CHAR_TABLE_KEY, myCharTable); - } - return rootNode; - } - - private static class ConvertFromTokensToASTBuilder implements DiffTreeChangeBuilder { - private final DiffTreeChangeBuilder myDelegate; - private final ASTConverter myConverter; - - public ConvertFromTokensToASTBuilder(StartMarker rootNode, DiffTreeChangeBuilder delegate) { - myDelegate = delegate; - myConverter = new ASTConverter(rootNode); - } - - @Override - public void nodeDeleted(@NotNull final ASTNode oldParent, @NotNull final ASTNode oldNode) { - myDelegate.nodeDeleted(oldParent, oldNode); - } - - @Override - public void nodeInserted(@NotNull final ASTNode oldParent, @NotNull final LighterASTNode newNode, final int pos) { - myDelegate.nodeInserted(oldParent, myConverter.convert((Node) newNode), pos); - } - - @Override - public void nodeReplaced(@NotNull final ASTNode oldChild, @NotNull final LighterASTNode newChild) { - ASTNode converted = myConverter.convert((Node) newChild); - myDelegate.nodeReplaced(oldChild, converted); - } - } - - @NonNls - private static final String UNBALANCED_MESSAGE = - "Unbalanced tree. Most probably caused by unbalanced markers. " + - "Try calling setDebugMode(true) against PsiBuilder passed to identify exact location of the problem"; - - @NotNull - private DiffLog merge(@NotNull final ASTNode oldRoot, @NotNull StartMarker newRoot) { - DiffLog diffLog = new DiffLog(); - final ConvertFromTokensToASTBuilder builder = new ConvertFromTokensToASTBuilder(newRoot, diffLog); - final MyTreeStructure treeStructure = new MyTreeStructure(newRoot, null); - final MyComparator comparator = new MyComparator(getUserDataUnprotected(CUSTOM_COMPARATOR), treeStructure); - - final ProgressIndicatorProvider provider = ProgressIndicatorProvider.getInstance(); - final ProgressIndicator indicator = provider != null ? provider.getProgressIndicator() : null; - BlockSupportImpl.diffTrees(oldRoot, builder, comparator, treeStructure, indicator); - return diffLog; - } - - @NotNull - private StartMarker prepareLightTree() { - markTokenTypeChecked(); - balanceWhiteSpaces(); - - LOG.assertTrue(!myProduction.isEmpty(), "Parser produced no markers. Text:\n" + myText); - - final StartMarker rootMarker = (StartMarker) myProduction.get(0); - rootMarker.myParent = rootMarker.myFirstChild = rootMarker.myLastChild = rootMarker.myNext = null; - StartMarker curNode = rootMarker; - final Stack nodes = new Stack(); - nodes.push(rootMarker); - - @SuppressWarnings({"MultipleVariablesInDeclaration"}) int lastErrorIndex = -1, maxDepth = 0, curDepth = 0; - for (int i = 1; i < myProduction.size(); i++) { - final ProductionMarker item = myProduction.get(i); - - if (curNode == null) LOG.error("Unexpected end of the production"); - - item.myParent = curNode; - if (item instanceof StartMarker) { - final StartMarker marker = (StartMarker) item; - marker.myFirstChild = marker.myLastChild = marker.myNext = null; - curNode.addChild(marker); - nodes.push(curNode); - curNode = marker; - curDepth++; - if (curDepth > maxDepth) maxDepth = curDepth; - } else if (item instanceof DoneMarker) { - if (((DoneMarker) item).myStart != curNode) LOG.error(UNBALANCED_MESSAGE); - curNode = nodes.pop(); - curDepth--; - } else if (item instanceof ErrorItem) { - int curToken = item.myLexemeIndex; - if (curToken == lastErrorIndex) continue; - lastErrorIndex = curToken; - curNode.addChild(item); - } - } - - if (myCurrentLexeme < myLexemeCount) { - final List missed = CollectionFactory.arrayList(myLexTypes, myCurrentLexeme, myLexemeCount); - LOG.error("Tokens " + missed + " were not inserted into the tree. Text:\n" + myText); - } - - if (rootMarker.myDoneMarker.myLexemeIndex < myLexemeCount) { - final List missed = CollectionFactory.arrayList(myLexTypes, rootMarker.myDoneMarker.myLexemeIndex, myLexemeCount); - LOG.error("Tokens " + missed + " are outside of root element \"" + rootMarker.myType + "\". Text:\n" + myText); - } - - if (myLexStarts.length <= myCurrentLexeme + 1) { - resizeLexemes(myCurrentLexeme + 1); - } - - myLexStarts[myCurrentLexeme] = myText.length(); // $ terminating token.; - myLexStarts[myCurrentLexeme + 1] = 0; - myLexTypes[myCurrentLexeme] = null; - - LOG.assertTrue(curNode == rootMarker, UNBALANCED_MESSAGE); - - checkTreeDepth(maxDepth, rootMarker.getTokenType() instanceof IFileElementType); - - return rootMarker; - } - - private void balanceWhiteSpaces() { - for (int i = 1; i < myProduction.size() - 1; i++) { - final ProductionMarker item = myProduction.get(i); - - if (item instanceof StartMarker && ((StartMarker) item).myDoneMarker == null) { - LOG.error(UNBALANCED_MESSAGE); - } - - final int prevProductionLexIndex = myProduction.get(i - 1).myLexemeIndex; - int idx = item.myLexemeIndex; - while (idx > prevProductionLexIndex && whitespaceOrComment(myLexTypes[idx - 1])) idx--; - final int wsStartIndex = idx; - - int wsEndIndex = item.myLexemeIndex; - while (wsEndIndex < myLexemeCount && whitespaceOrComment(myLexTypes[wsEndIndex])) wsEndIndex++; - - final List wsTokens = CollectionFactory.arrayList(myLexTypes, wsStartIndex, wsEndIndex); - final boolean atEnd = wsStartIndex == 0 || wsEndIndex == myLexemeCount; - final WhitespacesAndCommentsBinder.TokenTextGetter getter = new WhitespacesAndCommentsBinder.TokenTextGetter() { - @Override - public CharSequence get(final int i) { - return myText.subSequence(myLexStarts[wsStartIndex + i], myLexStarts[wsStartIndex + i + 1]); - } - }; - item.myLexemeIndex = wsStartIndex + item.myEdgeTokenBinder.getEdgePosition(wsTokens, atEnd, getter); - } - } - - private void checkTreeDepth(final int maxDepth, final boolean isFileRoot) { - if (myFile == null) return; - final PsiFile file = myFile.getOriginalFile(); - final Boolean flag = file.getUserData(BlockSupport.TREE_DEPTH_LIMIT_EXCEEDED); - if (maxDepth > BlockSupport.INCREMENTAL_REPARSE_DEPTH_LIMIT) { - if (!Boolean.TRUE.equals(flag)) { - file.putUserData(BlockSupport.TREE_DEPTH_LIMIT_EXCEEDED, Boolean.TRUE); - } - } else if (isFileRoot && flag != null) { - file.putUserData(BlockSupport.TREE_DEPTH_LIMIT_EXCEEDED, null); - } - } - - private void bind(final StartMarker rootMarker, final CompositeElement rootNode) { - StartMarker curMarker = rootMarker; - CompositeElement curNode = rootNode; - - int lexIndex = rootMarker.myLexemeIndex; - ProductionMarker item = rootMarker.myFirstChild != null ? rootMarker.myFirstChild : rootMarker.myDoneMarker; - while (true) { - lexIndex = insertLeaves(lexIndex, item.myLexemeIndex, curNode); - - if (item == rootMarker.myDoneMarker) break; - - if (item instanceof StartMarker) { - final StartMarker marker = (StartMarker) item; - if (!marker.myDoneMarker.myCollapse) { - curMarker = marker; - - final CompositeElement childNode = createComposite(marker); - curNode.rawAddChildrenWithoutNotifications(childNode); - curNode = childNode; - - item = marker.myFirstChild != null ? marker.myFirstChild : marker.myDoneMarker; - continue; - } else { - lexIndex = collapseLeaves(curNode, marker); - } - } else if (item instanceof ErrorItem) { - final CompositeElement errorElement = Factory.createErrorElement(((ErrorItem) item).myMessage); - curNode.rawAddChildrenWithoutNotifications(errorElement); - } else if (item instanceof DoneMarker) { - curMarker = (StartMarker) ((DoneMarker) item).myStart.myParent; - curNode = curNode.getTreeParent(); - item = ((DoneMarker) item).myStart; - } - - item = item.myNext != null ? item.myNext : curMarker.myDoneMarker; - } - } - - private int insertLeaves(int curToken, int lastIdx, final CompositeElement curNode) { - lastIdx = Math.min(lastIdx, myLexemeCount); - while (curToken < lastIdx) { - ProgressIndicatorProvider.checkCanceled(); - final int start = myLexStarts[curToken]; - final int end = myLexStarts[curToken + 1]; - if (start < end || myLexTypes[curToken] instanceof ILeafElementType) { // Empty token. Most probably a parser directive like indent/dedent in Python - final IElementType type = myLexTypes[curToken]; - final TreeElement leaf = createLeaf(type, start, end); - curNode.rawAddChildrenWithoutNotifications(leaf); - } - curToken++; - } - - return curToken; - } - - private int collapseLeaves(final CompositeElement ast, final StartMarker startMarker) { - final int start = myLexStarts[startMarker.myLexemeIndex]; - final int end = myLexStarts[startMarker.myDoneMarker.myLexemeIndex]; - final TreeElement leaf = createLeaf(startMarker.myType, start, end); - ast.rawAddChildrenWithoutNotifications(leaf); - return startMarker.myDoneMarker.myLexemeIndex; - } - - private static CompositeElement createComposite(final StartMarker marker) { - final IElementType type = marker.myType; - if (type == TokenType.ERROR_ELEMENT) { - String message = marker.myDoneMarker instanceof DoneWithErrorMarker ? ((DoneWithErrorMarker) marker.myDoneMarker).myMessage : null; - return Factory.createErrorElement(message); - } - - if (type == null) { - throw new RuntimeException(UNBALANCED_MESSAGE); - } - - return ASTFactory.composite(type); - } - - @Nullable - public static String getErrorMessage(final LighterASTNode node) { - if (node instanceof ErrorItem) return ((ErrorItem) node).myMessage; - if (node instanceof StartMarker) { - final StartMarker marker = (StartMarker) node; - if (marker.myType == TokenType.ERROR_ELEMENT && marker.myDoneMarker instanceof DoneWithErrorMarker) { - return ((DoneWithErrorMarker) marker.myDoneMarker).myMessage; - } - } - - return null; - } - - private static class MyComparator implements ShallowNodeComparator { - private final TripleFunction, ThreeState> custom; - private final MyTreeStructure myTreeStructure; - - private MyComparator(TripleFunction, ThreeState> custom, - MyTreeStructure treeStructure) { - this.custom = custom; - myTreeStructure = treeStructure; - } - - @Override - public ThreeState deepEqual(final ASTNode oldNode, final LighterASTNode newNode) { - ProgressIndicatorProvider.checkCanceled(); - - boolean oldIsErrorElement = oldNode instanceof PsiErrorElement; - boolean newIsErrorElement = newNode.getTokenType() == TokenType.ERROR_ELEMENT; - if (oldIsErrorElement != newIsErrorElement) return ThreeState.NO; - if (oldIsErrorElement && newIsErrorElement) { - final PsiErrorElement e1 = (PsiErrorElement) oldNode; - return Comparing.equal(e1.getErrorDescription(), getErrorMessage(newNode)) ? ThreeState.UNSURE : ThreeState.NO; - } - - if (newNode instanceof Token) { - final IElementType type = newNode.getTokenType(); - final Token token = (Token) newNode; - - if (oldNode instanceof ForeignLeafPsiElement) { - return type instanceof ForeignLeafType && ((ForeignLeafType) type).getValue().equals(oldNode.getText()) - ? ThreeState.YES - : ThreeState.NO; - } - - if (oldNode instanceof LeafElement) { - if (type instanceof ForeignLeafType) return ThreeState.NO; - - return ((LeafElement) oldNode).textMatches(token.getText()) - ? ThreeState.YES - : ThreeState.NO; - } - - if (type instanceof ILightLazyParseableElementType) { - return ((TreeElement) oldNode).textMatches(token.getText()) - ? ThreeState.YES - : TreeUtil.isCollapsedChameleon(oldNode) - ? ThreeState.NO // do not dive into collapsed nodes - : ThreeState.UNSURE; - } - - if (oldNode.getElementType() instanceof ILazyParseableElementType && type instanceof ILazyParseableElementType || - oldNode.getElementType() instanceof CustomParsingType && type instanceof CustomParsingType) { - return ((TreeElement) oldNode).textMatches(token.getText()) - ? ThreeState.YES - : ThreeState.NO; - } - } - if (custom != null) { - return custom.fun(oldNode, newNode, myTreeStructure); - } - - return ThreeState.UNSURE; - } - - @Override - public boolean typesEqual(final ASTNode n1, final LighterASTNode n2) { - if (n1 instanceof PsiWhiteSpaceImpl) { - return ourAnyLanguageWhitespaceTokens.contains(n2.getTokenType()) || - n2 instanceof Token && ((Token) n2).myBuilder.myWhitespaces.contains(n2.getTokenType()); - } - - return derefToken(n1.getElementType()) == derefToken(n2.getTokenType()); - } - - public static IElementType derefToken(IElementType probablyWrapper) { - if (probablyWrapper instanceof TokenWrapper) { - return derefToken(((TokenWrapper) probablyWrapper).getDelegate()); - } - return probablyWrapper; - } - - @Override - public boolean hashCodesEqual(final ASTNode n1, final LighterASTNode n2) { - if (n1 instanceof LeafElement && n2 instanceof Token) { - boolean isForeign1 = n1 instanceof ForeignLeafPsiElement; - boolean isForeign2 = n2.getTokenType() instanceof ForeignLeafType; - if (isForeign1 != isForeign2) return false; - - if (isForeign1 && isForeign2) { - return n1.getText().equals(((ForeignLeafType) n2.getTokenType()).getValue()); - } - - return ((LeafElement) n1).textMatches(((Token) n2).getText()); - } - - if (n1 instanceof PsiErrorElement && n2.getTokenType() == TokenType.ERROR_ELEMENT) { - final PsiErrorElement e1 = (PsiErrorElement) n1; - if (!Comparing.equal(e1.getErrorDescription(), getErrorMessage(n2))) return false; - } - - return ((TreeElement) n1).hc() == ((Node) n2).hc(); - } - } - - private static class MyTreeStructure implements FlyweightCapableTreeStructure { - private final LimitedPool myPool; - private final LimitedPool myLazyPool; - private final StartMarker myRoot; - - public MyTreeStructure(@NotNull StartMarker root, @Nullable final MyTreeStructure parentTree) { - if (parentTree == null) { - myPool = new LimitedPool(1000, new LimitedPool.ObjectFactory() { - @Override - public void cleanup(final Token token) { - token.clean(); - } - - @Override - public Token create() { - return new TokenNode(); - } - }); - myLazyPool = new LimitedPool(200, new LimitedPool.ObjectFactory() { - @Override - public void cleanup(final LazyParseableToken token) { - token.clean(); - } - - @Override - public LazyParseableToken create() { - return new LazyParseableToken(); - } - }); - } else { - myPool = parentTree.myPool; - myLazyPool = parentTree.myLazyPool; - } - myRoot = root; - } - - @Override - @NotNull - public LighterASTNode getRoot() { - return myRoot; - } - - @Override - public LighterASTNode getParent(@NotNull final LighterASTNode node) { - if (node instanceof StartMarker) { - return ((StartMarker) node).myParent; - } - throw new UnsupportedOperationException("Unknown node type: " + node); - } - - @Override - @NotNull - public LighterASTNode prepareForGetChildren(@NotNull final LighterASTNode node) { - return node; - } - - private int count; - - @Override - public int getChildren(@NotNull final LighterASTNode item, @NotNull final Ref into) { - if (item instanceof LazyParseableToken) { - final FlyweightCapableTreeStructure tree = ((LazyParseableToken) item).parseContents(); - final LighterASTNode root = tree.getRoot(); - return tree.getChildren(tree.prepareForGetChildren(root), into); // todo: set offset shift for kids? - } - - if (item instanceof Token || item instanceof ErrorItem) return 0; - StartMarker marker = (StartMarker) item; - - count = 0; - ProductionMarker child = marker.myFirstChild; - int lexIndex = marker.myLexemeIndex; - while (child != null) { - lexIndex = insertLeaves(lexIndex, child.myLexemeIndex, into, marker.myBuilder); - - if (child instanceof StartMarker && ((StartMarker) child).myDoneMarker.myCollapse) { - int lastIndex = ((StartMarker) child).myDoneMarker.myLexemeIndex; - insertLeaf(into, child.getTokenType(), marker.myBuilder, child.myLexemeIndex, lastIndex); - } else { - ensureCapacity(into); - into.get()[count++] = child; - } - - if (child instanceof StartMarker) { - lexIndex = ((StartMarker) child).myDoneMarker.myLexemeIndex; - } - child = child.myNext; - } - - insertLeaves(lexIndex, marker.myDoneMarker.myLexemeIndex, into, marker.myBuilder); - - return count; - } - - @Override - public void disposeChildren(final LighterASTNode[] nodes, final int count) { - if (nodes == null) return; - for (int i = 0; i < count; i++) { - final LighterASTNode node = nodes[i]; - if (node instanceof LazyParseableToken) { - myLazyPool.recycle((LazyParseableToken) node); - } else if (node instanceof Token) { - myPool.recycle((Token) node); - } - } - } - - private void ensureCapacity(final Ref into) { - LighterASTNode[] old = into.get(); - if (old == null) { - old = new LighterASTNode[10]; - into.set(old); - } else if (count >= old.length) { - LighterASTNode[] newStore = new LighterASTNode[count * 3 / 2]; - System.arraycopy(old, 0, newStore, 0, count); - into.set(newStore); - } - } - - private int insertLeaves(int curToken, int lastIdx, Ref into, PsiBuilderImpl builder) { - lastIdx = Math.min(lastIdx, builder.myLexemeCount); - while (curToken < lastIdx) { - insertLeaf(into, builder.myLexTypes[curToken], builder, curToken, curToken + 1); - - curToken++; - } - return curToken; - } - - private void insertLeaf(Ref into, IElementType type, PsiBuilderImpl builder, int startLexemIndex, int endLexemIndex) { - final int start = builder.myLexStarts[startLexemIndex]; - final int end = builder.myLexStarts[endLexemIndex]; - if (start > end || ((start == end) && !(type instanceof ILeafElementType))) return; - - final Token lexeme; - if (type instanceof ILightLazyParseableElementType) { - lexeme = myLazyPool.alloc(); - LazyParseableToken lazyParseableToken = (LazyParseableToken) lexeme; - lazyParseableToken.myParent = this; - lazyParseableToken.myStartIndex = startLexemIndex; - lazyParseableToken.myEndIndex = endLexemIndex; - } else { - lexeme = myPool.alloc(); - } - lexeme.myBuilder = builder; - lexeme.myTokenType = type; - lexeme.myTokenStart = start; - lexeme.myTokenEnd = end; - ensureCapacity(into); - into.get()[count++] = lexeme; - } - } - - private static class ASTConverter implements Convertor { - private final StartMarker myRoot; - - public ASTConverter(final StartMarker root) { - myRoot = root; - } - - @Override - public ASTNode convert(final Node n) { - if (n instanceof Token) { - final Token token = (Token) n; - return token.myBuilder.createLeaf(token.getTokenType(), token.myTokenStart, token.myTokenEnd); - } else if (n instanceof ErrorItem) { - return Factory.createErrorElement(((ErrorItem) n).myMessage); - } else { - final StartMarker startMarker = (StartMarker) n; - final CompositeElement composite = n == myRoot ? (CompositeElement) myRoot.myBuilder.createRootAST(myRoot) - : createComposite(startMarker); - startMarker.myBuilder.bind(startMarker, composite); - return composite; - } - } - } - - @Override - public void setDebugMode(boolean dbgMode) { - myDebugMode = dbgMode; - } - - public Lexer getLexer() { - return myLexer; - } - - @NotNull - private TreeElement createLeaf(final IElementType type, final int start, final int end) { - CharSequence text = myCharTable.intern(myText, start, end); - if (myWhitespaces.contains(type)) { - return new PsiWhiteSpaceImpl(text); - } - - if (type instanceof CustomParsingType) { - return (TreeElement) ((CustomParsingType) type).parse(text, myCharTable); - } - - if (type instanceof ILazyParseableElementType) { - return ASTFactory.lazy((ILazyParseableElementType) type, text); - } - - return ASTFactory.leaf(type, text); - } - - /** - * just to make removeRange method available. - */ - private static class MyList extends ArrayList { - private static final Field ourElementDataField; - - static { - Field f = null; - /*try { - f = ArrayList.class.getDeclaredField("elementData"); - f.setAccessible(true); - } - catch(NoSuchFieldException e) { - // IBM J9 does not have the field - f = null; - - }*/ - ourElementDataField = f; - } - - private Object[] cachedElementData; - - @Override - public void removeRange(final int fromIndex, final int toIndex) { - super.removeRange(fromIndex, toIndex); - } - - MyList() { - super(256); - } - - @Override - public int lastIndexOf(final Object o) { - if (cachedElementData == null) return super.lastIndexOf(o); - for (int i = size() - 1; i >= 0; i--) { - if (cachedElementData[i] == o) return i; - } - return -1; - } - - @Override - public void ensureCapacity(final int minCapacity) { - if (cachedElementData == null || minCapacity >= cachedElementData.length) { - super.ensureCapacity(minCapacity); - initCachedField(); - } - } - - private void initCachedField() { - if (ourElementDataField == null) return; - try { - cachedElementData = (Object[]) ourElementDataField.get(this); - } catch (Exception e) { - LOG.error(e); - } - } - } - - @SuppressWarnings("unchecked") - @Override - public T getUserDataUnprotected(@NotNull final Key key) { - if (key == FileContextUtil.CONTAINING_FILE_KEY) return (T) myFile; - return myUserData != null ? (T) myUserData.get(key) : null; - } - - @Override - public void putUserDataUnprotected(@NotNull final Key key, @Nullable final T value) { - if (myUserData == null) myUserData = CollectionFactory.hashMap(); - myUserData.put(key, value); - } -} diff --git a/idea_fix/src/com/intellij/openapi/editor/impl/CharArray.java b/idea_fix/src/com/intellij/openapi/editor/impl/CharArray.java deleted file mode 100644 index 533162bb0b0..00000000000 --- a/idea_fix/src/com/intellij/openapi/editor/impl/CharArray.java +++ /dev/null @@ -1,668 +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.openapi.editor.impl; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.impl.event.DocumentEventImpl; -import com.intellij.util.LocalTimeCounter; -import com.intellij.util.text.CharArrayCharSequence; -import com.intellij.util.text.CharArrayUtil; -import com.intellij.util.text.CharSequenceBackedByArray; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.ref.SoftReference; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - -/** - * @author cdr - */ -abstract class CharArray implements CharSequenceBackedByArray { - - @SuppressWarnings("UseOfArchaicSystemPropertyAccessors") - private static final boolean DISABLE_DEFERRED_PROCESSING = false; - @SuppressWarnings("UseOfArchaicSystemPropertyAccessors") - private static final boolean DEBUG_DEFERRED_PROCESSING = false; - - private static final Logger LOG = Logger.getInstance("#" + CharArray.class.getName()); - - /** - * We can't exclude possibility of situation when 'defer changes' state is {@link #setDeferredChangeMode(boolean) entered} - * but not exited, hence, we want to perform automatic flushing if necessary in order to avoid memory leaks. This constant holds - * a value that defines that 'automatic flushing' criteria, i.e. every time number of stored deferred changes exceeds this value, - * they are automatically flushed. - */ - private static final int MAX_DEFERRED_CHANGES_NUMBER = 10000; - - private final AtomicReference myDeferredChangesStorage = new AtomicReference(); - - private int myStart; - /** - * This class implements {@link #subSequence(int, int)} by creating object of the same class that partially shares the same - * data as the object on which the method is called. So, this field may define interested end offset (if it's non-negative). - */ - private int myEnd = -1; - private int myCount = 0; - - private CharSequence myOriginalSequence; - private char[] myArray; - private SoftReference myStringRef; // buffers String value - for not to generate it every time - private int myBufferSize; - private int myDeferredShift; - private boolean myDeferredChangeMode; - - // We had a problems with bulk document text processing, hence, debug facilities were introduced. The fields group below work with them. - // The main idea is to hold all history of bulk processing iteration in order to be able to retrieve it from client and reproduce the - // problem. - - /** - * Flag the identifies if current char array should debug bulk processing. - */ - private final boolean myDebugDeferredProcessing; - - /** - * Duplicate instance of the current char array that is used during debug processing as follows - apply every text change - * from the bulk changes group to this instance immediately in order to be able to check if the current 'deferred change-aware' - * instance functionally behaves at the same way as 'straightforward' one. - */ - private CharArray myDebugArray; - - /** - * Holds deferred changes create during the current bulk processing iteration. - */ - private List myDebugDeferredChanges; - - /** - * Document text on bulk processing start. - */ - private String myDebugTextOnBatchUpdateStart; - - // max chars to hold, bufferSize == 0 means unbounded - CharArray(int bufferSize) { - this(bufferSize, new TextChangesStorage(), null, -1, -1); - } - - private CharArray(final int bufferSize, @NotNull TextChangesStorage deferredChangesStorage, @Nullable char[] data, int start, int end) { - this(bufferSize, deferredChangesStorage, data, start, end, DEBUG_DEFERRED_PROCESSING); - } - - private CharArray(final int bufferSize, @NotNull TextChangesStorage deferredChangesStorage, @Nullable char[] data, int start, int end, - boolean debugDeferredProcessing) { - myBufferSize = bufferSize; - myDeferredChangesStorage.set(deferredChangesStorage); - if (data == null) { - myOriginalSequence = ""; - } else { - myArray = data; - myCount = end - start; - } - if (start >= 0 && end >= 0) { - myStart = start; - myEnd = end; - } - - myDebugDeferredProcessing = debugDeferredProcessing; - if (myDebugDeferredProcessing) { - - myDebugArray = new CharArray(bufferSize, new TextChangesStorage(), data == null ? null : Arrays.copyOf(data, data.length), - start, end, false) { - @NotNull - @Override - protected DocumentEvent beforeChangedUpdate(DocumentImpl subj, - int offset, - CharSequence oldString, - CharSequence newString, - boolean wholeTextReplaced) { - return new DocumentEventImpl(subj, offset, oldString, newString, -1, wholeTextReplaced); - } - - @Override - protected void afterChangedUpdate(@NotNull DocumentEvent event, long newModificationStamp) { - } - }; - myDebugDeferredChanges = new ArrayList(); - } - } - - public void setBufferSize(int bufferSize) { - myBufferSize = bufferSize; - } - - @NotNull - protected abstract DocumentEvent beforeChangedUpdate(DocumentImpl subj, - int offset, - @Nullable CharSequence oldString, - @Nullable CharSequence newString, - boolean wholeTextReplaced); - - protected abstract void afterChangedUpdate(@NotNull DocumentEvent event, long newModificationStamp); - - public void setText(@Nullable final DocumentImpl subj, final CharSequence chars) { - myOriginalSequence = chars; - myArray = null; - myCount = chars.length(); - myStringRef = null; - TextChangesStorage storage = myDeferredChangesStorage.get(); - storage.getLock().lock(); - try { - if (isSubSequence()) { - myDeferredChangesStorage.set(new TextChangesStorage()); - myStart = 0; - myEnd = -1; - } else { - storage.clear(); - } - } finally { - storage.getLock().unlock(); - } - - if (subj != null) { - trimToSize(subj); - } - - if (myDebugDeferredProcessing) { - myDebugArray.setText(subj, chars); - myDebugDeferredChanges.clear(); - } - } - - public void replace(DocumentImpl subj, - int startOffset, int endOffset, CharSequence toDelete, CharSequence newString, long newModificationStamp, - boolean wholeTextReplaced) { - final DocumentEvent event = beforeChangedUpdate(subj, startOffset, toDelete, newString, wholeTextReplaced); - startOffset += myStart; - endOffset += myStart; - doReplace(startOffset, endOffset, newString); - afterChangedUpdate(event, newModificationStamp); - } - - private void doReplace(int startOffset, int endOffset, CharSequence newString) { - prepareForModification(); - - if (isDeferredChangeMode()) { - storeChange(new TextChangeImpl(newString, startOffset, endOffset)); - if (myDebugDeferredProcessing) { - myDebugArray.doReplace(startOffset, endOffset, newString); - } - return; - } - - int newLength = newString.length(); - int oldLength = endOffset - startOffset; - - CharArrayUtil.getChars(newString, myArray, startOffset, Math.min(newLength, oldLength)); - - if (newLength > oldLength) { - doInsert(newString.subSequence(oldLength, newLength), endOffset); - } else if (newLength < oldLength) { - doRemove(startOffset + newLength, startOffset + oldLength); - } - } - - public void remove(DocumentImpl subj, int startIndex, int endIndex, CharSequence toDelete) { - DocumentEvent event = beforeChangedUpdate(subj, startIndex, toDelete, null, false); - startIndex += myStart; - endIndex += myStart; - doRemove(startIndex, endIndex); - afterChangedUpdate(event, LocalTimeCounter.currentTime()); - } - - private void doRemove(final int startIndex, final int endIndex) { - if (startIndex == endIndex) { - return; - } - prepareForModification(); - - if (isDeferredChangeMode()) { - storeChange(new TextChangeImpl("", startIndex, endIndex)); - if (myDebugDeferredProcessing) { - myDebugArray.doRemove(startIndex, endIndex); - } - return; - } - - if (endIndex < myCount) { - System.arraycopy(myArray, endIndex, myArray, startIndex, myCount - endIndex); - } - myCount -= endIndex - startIndex; - } - - public void insert(DocumentImpl subj, CharSequence s, int startIndex) { - DocumentEvent event = beforeChangedUpdate(subj, startIndex, null, s, false); - startIndex += myStart; - doInsert(s, startIndex); - - afterChangedUpdate(event, LocalTimeCounter.currentTime()); - trimToSize(subj); - } - - private void doInsert(final CharSequence s, final int startIndex) { - prepareForModification(); - - if (isDeferredChangeMode()) { - storeChange(new TextChangeImpl(s, startIndex)); - if (myDebugDeferredProcessing) { - myDebugArray.doInsert(s, startIndex); - } - return; - } - - int insertLength = s.length(); - myArray = relocateArray(myArray, myCount + insertLength); - if (startIndex < myCount) { - System.arraycopy(myArray, startIndex, myArray, startIndex + insertLength, myCount - startIndex); - } - - CharArrayUtil.getChars(s, myArray, startIndex); - myCount += insertLength; - } - - /** - * Stores given change at collection of deferred changes (merging it with others if necessary) and updates current object - * state ({@link #length() length} etc). - * - * @param change new change to store - */ - private void storeChange(@NotNull TextChangeImpl change) { - if (!change.isWithinBounds(length())) { - LOG.error(String.format( - "Invalid change attempt detected - given change bounds are not within the current char array. Change: %d:%d-%d", - change.getText().length(), change.getStart(), change.getEnd() - ), dumpState()); - return; - } - TextChangesStorage storage = myDeferredChangesStorage.get(); - storage.getLock().lock(); - try { - doStoreChange(change); - } finally { - storage.getLock().unlock(); - } - } - - private void doStoreChange(@NotNull TextChangeImpl change) { - TextChangesStorage storage = myDeferredChangesStorage.get(); - if (storage.size() >= MAX_DEFERRED_CHANGES_NUMBER) { - flushDeferredChanged(storage); - } - storage.store(change); - myDeferredShift += change.getDiff(); - - if (myDebugDeferredProcessing) { - myDebugDeferredChanges.add(change); - } - } - - private void prepareForModification() { - if (myOriginalSequence != null) { - myArray = new char[myOriginalSequence.length()]; - CharArrayUtil.getChars(myOriginalSequence, myArray, 0); - myOriginalSequence = null; - } - myStringRef = null; - } - - public CharSequence getCharArray() { - if (myOriginalSequence != null) return myOriginalSequence; - return this; - } - - public String toString() { - String str = myStringRef != null ? myStringRef.get() : null; - if (str == null) { - if (myOriginalSequence != null) { - str = myOriginalSequence.toString(); - } else if (!hasDeferredChanges()) { - str = new String(myArray, myStart, myCount); - } else { - str = substring(0, length()).toString(); - } - myStringRef = new SoftReference(str); - } - if (myDebugDeferredProcessing && isDeferredChangeMode()) { - String expected = myDebugArray.toString(); - checkStrings("toString()", expected, str); - } - return str; - } - - @Override - public final int length() { - final int result = myCount + myDeferredShift; - if (myDebugDeferredProcessing && isDeferredChangeMode()) { - int expected = myDebugArray.length(); - if (expected != result) { - dumpDebugInfo(String.format("Incorrect length() processing. Expected: '%s', actual: '%s'", expected, result)); - } - } - return result; - } - - @Override - public final char charAt(int i) { - if (i < 0 || i >= length()) { - throw new IndexOutOfBoundsException("Wrong offset: " + i + "; count:" + length()); - } - i += myStart; - if (myOriginalSequence != null) return myOriginalSequence.charAt(i); - final char result; - if (hasDeferredChanges()) { - TextChangesStorage storage = myDeferredChangesStorage.get(); - storage.getLock().lock(); - try { - result = storage.charAt(myArray, i); - } finally { - storage.getLock().unlock(); - } - } else { - result = myArray[i]; - } - - if (myDebugDeferredProcessing && isDeferredChangeMode()) { - char expected = myDebugArray.charAt(i); - if (expected != result) { - dumpDebugInfo( - String.format("Incorrect charAt() processing for index %d. Expected: '%c', actual: '%c'", i, expected, result) - ); - } - } - return result; - } - - @Override - public CharSequence subSequence(final int start, final int end) { - if (start == 0 && end == length()) return this; - if (myOriginalSequence != null) { - return myOriginalSequence.subSequence(start, end); - } - if (hasDeferredChanges()) { - return new CharArray(myBufferSize, myDeferredChangesStorage.get(), myArray, myStart + start, myStart + end) { - @NotNull - @Override - protected DocumentEvent beforeChangedUpdate(DocumentImpl subj, - int offset, - CharSequence oldString, - CharSequence newString, - boolean wholeTextReplaced) { - return new DocumentEventImpl(subj, offset, oldString, newString, LocalTimeCounter.currentTime(), wholeTextReplaced); - } - - @Override - protected void afterChangedUpdate(@NotNull DocumentEvent event, long newModificationStamp) { - } - - @Override - public char[] getChars() { - char[] chars = CharArray.this.getChars(); - char[] result = new char[end - start]; - System.arraycopy(chars, start, result, 0, result.length); - return result; - } - }; - } else { - // We don't use the same approach as with 'defer changes' mode because the former is the new experimental one and this one - // is rather mature, hence, we just minimizes the risks that something is wrong within the new approach. - return new CharArrayCharSequence(myArray, start, end); - } - } - - private boolean isSubSequence() { - return myEnd >= 0; - } - - @Override - public char[] getChars() { - if (myOriginalSequence != null) { - if (myArray == null) { - myArray = CharArrayUtil.fromSequence(myOriginalSequence); - } - } - flushDeferredChanged(myDeferredChangesStorage.get()); - if (myDebugDeferredProcessing && isDeferredChangeMode()) { - char[] expected = myDebugArray.getChars(); - for (int i = 0, max = length(); i < max; i++) { - if (myArray[i] != expected[i]) { - dumpDebugInfo(String.format("getChars(). Index: %d, expected: %c, actual: %c", i, expected[i], myArray[i])); - break; - } - } - } - return myArray; - } - - @Override - public void getChars(final char[] dst, final int dstOffset) { - flushDeferredChanged(myDeferredChangesStorage.get()); - if (myOriginalSequence != null) { - CharArrayUtil.getChars(myOriginalSequence, dst, dstOffset); - } else { - System.arraycopy(myArray, myStart, dst, dstOffset, length()); - } - - if (myDebugDeferredProcessing && isDeferredChangeMode()) { - char[] expected = new char[dst.length]; - myDebugArray.getChars(expected, dstOffset); - for (int i = dstOffset, j = myStart; i < dst.length && j < myArray.length; i++, j++) { - if (expected[i] != myArray[j]) { - dumpDebugInfo(String.format("getChars(char[], int). Given array of length %d, offset %d. Found char '%c' at index %d, " + - "expected to find '%c'", dst.length, dstOffset, myArray[j], i, expected[i])); - break; - } - } - } - } - - public CharSequence substring(final int start, final int end) { - if (start == end) return ""; - final CharSequence result; - if (myOriginalSequence == null) { - TextChangesStorage storage = myDeferredChangesStorage.get(); - storage.getLock().lock(); - try { - result = storage.substring(myArray, start + myStart, end + myStart); - } finally { - storage.getLock().unlock(); - } - } else { - result = myOriginalSequence.subSequence(start, end); - } - - if (myDebugDeferredProcessing && isDeferredChangeMode()) { - String expected = myDebugArray.substring(start, end).toString(); - checkStrings(String.format("substring(%d, %d)", start, end), expected, result.toString()); - } - return result; - } - - private static char[] relocateArray(char[] array, int index) { - if (index < array.length) { - return array; - } - - int newArraySize = array.length; - if (newArraySize == 0) { - newArraySize = 16; - } - while (newArraySize <= index) { - newArraySize = newArraySize * 12 / 10 + 1; - } - char[] newArray = new char[newArraySize]; - System.arraycopy(array, 0, newArray, 0, array.length); - return newArray; - } - - private void trimToSize(DocumentImpl subj) { - if (myBufferSize != 0 && length() > myBufferSize) { - flushDeferredChanged(myDeferredChangesStorage.get()); - // make a copy - remove(subj, 0, myCount - myBufferSize, getCharArray().subSequence(0, myCount - myBufferSize).toString()); - } - } - - /** - * @return true if this object is at {@link #setDeferredChangeMode(boolean) defer changes} mode; - * false otherwise - */ - public boolean isDeferredChangeMode() { - return !DISABLE_DEFERRED_PROCESSING && myDeferredChangeMode; - } - - public boolean hasDeferredChanges() { - return !myDeferredChangesStorage.get().isEmpty(); - } - - /** - * There is a possible case that client of this class wants to perform great number of modifications in a short amount of time - * (e.g. end-user performs formatting of the document backed by the object of the current class). It may result in significant - * performance degradation is the changes are performed one by one (every time the change is applied tail content is shifted to - * the left or right). So, we may want to optimize that by avoiding actual array modification until information about - * all target changes is provided and perform array data moves only after that. - *

- * This method allows to define that 'defer changes' mode usages, i.e. expected usage pattern is as follows: - *

-     * 
    - *
  1. - * Client of this class enters 'defer changes' mode (calls this method with 'true' argument). - * That means that all subsequent changes will not actually modify backed array data and will be stored separately; - *
  2. - *
  3. - * Number of target changes are applied to the current object via standard API - * ({@link #insert(com.intellij.openapi.editor.impl.DocumentImpl, CharSequence, int) insert}, - * {@link #remove(com.intellij.openapi.editor.impl.DocumentImpl, int, int, CharSequence) remove} and - * {@link #replace(com.intellij.openapi.editor.impl.DocumentImpl, int, int, CharSequence, CharSequence, long, boolean) replace}); - *
  4. - *
  5. - * Client of this class indicates that 'massive change time' is over by calling this method with 'false' - * argument. That flushes all deferred changes (if any) to the backed data array and makes every subsequent change to - * be immediate flushed to the backed array; - *
  6. - *
- *
- *

- * Note: we can't exclude possibility that 'defer changes' mode is started but inadvertently not ended - * (due to programming error, unexpected exception etc). Hence, this class is free to automatically end - * 'defer changes' mode when necessary in order to avoid memory leak with infinite deferred changes storing. - * - * @param deferredChangeMode flag that defines if 'defer changes' mode should be used by the current object - */ - public void setDeferredChangeMode(boolean deferredChangeMode) { - if (deferredChangeMode && myDebugDeferredProcessing) { - myDebugArray.setText(null, myDebugTextOnBatchUpdateStart = toString()); - myDebugDeferredChanges.clear(); - } - myDeferredChangeMode = deferredChangeMode; - if (!deferredChangeMode) { - flushDeferredChanged(myDeferredChangesStorage.get()); - } - } - - private void flushDeferredChanged(@NotNull TextChangesStorage storage) { - storage.getLock().lock(); - try { - doFlushDeferredChanged(); - } finally { - storage.getLock().unlock(); - } - } - - private void doFlushDeferredChanged() { - TextChangesStorage storage = myDeferredChangesStorage.get(); - List changes = storage.getChanges(); - if (changes.isEmpty()) { - return; - } - - char[] beforeMerge = null; - final boolean inPlace; - if (myDebugDeferredProcessing) { - beforeMerge = new char[myArray.length]; - System.arraycopy(myArray, 0, beforeMerge, 0, myArray.length); - } - - BulkChangesMerger changesMerger = BulkChangesMerger.INSTANCE; - if (myArray.length < length()) { - myArray = changesMerger.mergeToCharArray(myArray, myCount, changes); - inPlace = false; - } else { - changesMerger.mergeInPlace(myArray, myCount, changes); - inPlace = true; - } - - if (myDebugDeferredProcessing) { - for (int i = 0, max = length(); i < max; i++) { - if (myArray[i] != myDebugArray.myArray[i]) { - dumpDebugInfo(String.format( - "flushDeferredChanged(). Index %d, expected: '%c', actual '%c'. Text before merge: '%s', merge inplace: %b", - i, myDebugArray.myArray[i], myArray[i], Arrays.toString(beforeMerge), inPlace)); - break; - } - } - } - - myCount += myDeferredShift; - myDeferredShift = 0; - storage.clear(); - myDeferredChangeMode = false; - } - - @NotNull - public String dumpState() { - return String.format( - "deferred changes mode: %b, length: %d (data array length: %d, deferred shift: %d); view offsets: [%d; %d]; deferred changes: %s", - isDeferredChangeMode(), length(), myCount, myDeferredShift, myStart, myEnd, myDeferredChangesStorage - ); - } - - private void checkStrings(@NotNull String operation, @NotNull String expected, @NotNull String actual) { - if (expected.equals(actual)) { - return; - } - for (int i = 0, max = Math.min(expected.length(), actual.length()); i < max; i++) { - if (actual.charAt(i) != expected.charAt(i)) { - dumpDebugInfo(String.format( - "Incorrect %s processing. Expected length: %d, actual length: %d. Unmatched symbol at %d - expected: '%c', " + - "actual: '%c', expected document: '%s', actual document: '%s'", - operation, expected.length(), actual.length(), i, expected.charAt(i), actual.charAt(i), expected, actual - )); - return; - } - } - dumpDebugInfo(String.format( - "Incorrect %s processing. Expected length: %d, actual length: %d, expected: '%s', actual: '%s'", - operation, expected.length(), actual.length(), expected, actual - )); - } - - private void dumpDebugInfo(@NotNull String problem) { - //LOG.error(String.format( - // "/***********************************************************\n" + - // " * Please email idea.log to Denis.Zhdanov@jetbrains.com\n" + - // " ***********************************************************/\n" + - // "Incorrect CharArray processing detected: '%s'. Start: %d, end: %d, text on batch update start: '%s', deferred changes history: %s, " - // + "current deferred changes: %s", - // problem, myStart, myEnd, myDebugTextOnBatchUpdateStart, myDebugDeferredChanges, myDeferredChangesStorage - //)); - LOG.error(String.format( - "Incorrect CharArray processing detected: '%s'. Start: %d, end: %d, text on batch update start: '%s', deferred changes history: %s, " - + "current deferred changes: %s", - problem, myStart, myEnd, myDebugTextOnBatchUpdateStart, myDebugDeferredChanges, myDeferredChangesStorage - )); - } -} diff --git a/idea_fix/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java b/idea_fix/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java deleted file mode 100644 index 35114b8b85e..00000000000 --- a/idea_fix/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright 2000-2009 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.fileEditor.impl; - -import com.intellij.lang.properties.charset.Native2AsciiCharset; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileTypes.BinaryFileDecompiler; -import com.intellij.openapi.fileTypes.BinaryFileTypeDecompilers; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.LanguageFileType; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Trinity; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.encoding.EncodingRegistry; -import com.intellij.testFramework.LightVirtualFile; -import com.intellij.util.ArrayUtil; -import com.intellij.util.text.CharArrayUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.UnsupportedCharsetException; - -public final class LoadTextUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.LoadTextUtil"); - private static final Key DETECTED_LINE_SEPARATOR_KEY = Key.create("DETECTED_LINE_SEPARATOR_KEY"); - - private LoadTextUtil() { - } - - @NotNull - private static Pair convertLineSeparators(@NotNull CharBuffer buffer) { - int dst = 0; - char prev = ' '; - int crCount = 0; - int lfCount = 0; - int crlfCount = 0; - - final int length = buffer.length(); - final char[] bufferArray = CharArrayUtil.fromSequenceWithoutCopying(buffer); - - for (int src = 0; src < length; src++) { - char c = bufferArray != null ? bufferArray[src] : buffer.charAt(src); - switch (c) { - case '\r': - buffer.put(dst++, '\n'); - crCount++; - break; - case '\n': - if (prev == '\r') { - crCount--; - crlfCount++; - } else { - buffer.put(dst++, '\n'); - lfCount++; - } - break; - default: - buffer.put(dst++, c); - break; - } - prev = c; - } - - String detectedLineSeparator = null; - if (crlfCount > crCount && crlfCount > lfCount) { - detectedLineSeparator = "\r\n"; - } else if (crCount > lfCount) { - detectedLineSeparator = "\r"; - } else if (lfCount > 0) { - detectedLineSeparator = "\n"; - } - - CharSequence result = buffer.length() == dst ? buffer : buffer.subSequence(0, dst); - return Pair.create(result, detectedLineSeparator); - } - - private static Charset detectCharset(@NotNull VirtualFile virtualFile, @NotNull byte[] content) { - if (virtualFile.isCharsetSet()) return virtualFile.getCharset(); - - Charset charset = doDetectCharset(virtualFile, content); - charset = charset == null ? EncodingRegistry.getInstance().getDefaultCharset() : charset; - if (EncodingRegistry.getInstance().isNative2Ascii(virtualFile)) { - charset = Native2AsciiCharset.wrap(charset); - } - virtualFile.setCharset(charset); - return charset; - } - - @NotNull - public static Charset detectCharsetAndSetBOM(@NotNull VirtualFile virtualFile, @NotNull byte[] content) { - return doDetectCharsetAndSetBOM(virtualFile, content).getFirst(); - } - - @NotNull - private static Pair doDetectCharsetAndSetBOM(@NotNull VirtualFile virtualFile, @NotNull byte[] content) { - Charset charset = detectCharset(virtualFile, content); - Pair bomAndCharset = getBOMAndCharset(content, charset); - final byte[] bom = bomAndCharset.second; - if (bom.length != 0) { - virtualFile.setBOM(bom); - } - return bomAndCharset; - } - - private static Charset doDetectCharset(@NotNull VirtualFile virtualFile, @NotNull byte[] content) { - Trinity guessed = guessFromContent(virtualFile, content, content.length); - if (guessed != null && guessed.first != null) return guessed.first; - - FileType fileType = virtualFile.getFileType(); - String charsetName = fileType.getCharset(virtualFile, content); - - if (charsetName == null) { - Charset saved = EncodingRegistry.getInstance().getEncoding(virtualFile, true); - if (saved != null) return saved; - } - return CharsetToolkit.forName(charsetName); - } - - @Nullable("null means no luck, otherwise it's tuple(guessed encoding, hint about content if was unable to guess, BOM)") - public static Trinity guessFromContent(VirtualFile virtualFile, byte[] content, int length) { - EncodingRegistry settings = EncodingRegistry.getInstance(); - boolean shouldGuess = settings != null && settings.isUseUTFGuessing(virtualFile); - CharsetToolkit toolkit = shouldGuess ? new CharsetToolkit(content, EncodingRegistry.getInstance().getDefaultCharset()) : null; - setCharsetWasDetectedFromBytes(virtualFile, false); - if (shouldGuess) { - toolkit.setEnforce8Bit(true); - Charset charset = toolkit.guessFromBOM(); - if (charset != null) { - setCharsetWasDetectedFromBytes(virtualFile, true); - byte[] bom = CharsetToolkit.getBom(charset); - if (bom == null) bom = CharsetToolkit.UTF8_BOM; - return Trinity.create(charset, null, bom); - } - CharsetToolkit.GuessedEncoding guessed = toolkit.guessFromContent(length); - if (guessed == CharsetToolkit.GuessedEncoding.VALID_UTF8) { - setCharsetWasDetectedFromBytes(virtualFile, true); - return Trinity.create(CharsetToolkit.UTF8_CHARSET, null, null); //UTF detected, ignore all directives - } - return Trinity.create(null, guessed, null); - } - return null; - } - - @NotNull - private static Pair getBOMAndCharset(@NotNull byte[] content, final Charset charset) { - if (charset != null && charset.name().contains(CharsetToolkit.UTF8) && CharsetToolkit.hasUTF8Bom(content)) { - return Pair.create(charset, CharsetToolkit.UTF8_BOM); - } - try { - if (CharsetToolkit.hasUTF16LEBom(content)) { - return Pair.create(CharsetToolkit.UTF_16LE_CHARSET, CharsetToolkit.UTF16LE_BOM); - } - if (CharsetToolkit.hasUTF16BEBom(content)) { - return Pair.create(CharsetToolkit.UTF_16BE_CHARSET, CharsetToolkit.UTF16BE_BOM); - } - } catch (UnsupportedCharsetException ignore) { - } - if (charset == null) { - return Pair.create(Charset.defaultCharset(), CharsetToolkit.UTF8_BOM); - } - return Pair.create(charset, ArrayUtil.EMPTY_BYTE_ARRAY); - } - - /** - * Gets the Writer for this file and sets modification stamp and time stamp to the specified values - * after closing the Writer.

- *

- * Normally you should not use this method. - * - * @param project - * @param virtualFile - * @param requestor any object to control who called this method. Note that - * it is considered to be an external change if requestor is null. - * See {@link com.intellij.openapi.vfs.VirtualFileEvent#getRequestor} - * @param text - * @param newModificationStamp new modification stamp or -1 if no special value should be set @return Writer - * @throws java.io.IOException if an I/O error occurs - * @see com.intellij.openapi.vfs.VirtualFile#getModificationStamp() - */ - @SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"}) - public static Writer getWriter(@Nullable Project project, @NotNull VirtualFile virtualFile, Object requestor, @NotNull String text, final long newModificationStamp) - throws IOException { - Charset existing = virtualFile.getCharset(); - Charset specified = extractCharsetFromFileContent(project, virtualFile, text); - Charset charset = chooseMostlyHarmlessCharset(existing, specified, text); - if (charset != null) { - if (!charset.equals(existing)) { - virtualFile.setCharset(charset); - } - setDetectedFromBytesFlagBack(virtualFile, charset, text); - } - - // in c ase of "UTF-16", OutputStreamWriter sometimes adds BOM on it's own. - // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6800103 - byte[] bom = virtualFile.getBOM(); - Charset fromBom = bom == null ? null : CharsetToolkit.guessFromBOM(bom); - if (fromBom != null) charset = fromBom; - - OutputStream outputStream = virtualFile.getOutputStream(requestor, newModificationStamp, -1); - OutputStreamWriter writer = charset == null ? new OutputStreamWriter(outputStream) : new OutputStreamWriter(outputStream, charset); - // no need to buffer ByteArrayOutputStream - return outputStream instanceof ByteArrayOutputStream ? writer : new BufferedWriter(writer); - } - - private static void setDetectedFromBytesFlagBack(@NotNull VirtualFile virtualFile, @NotNull Charset charset, @NotNull String text) { - if (virtualFile.getBOM() != null) { - // prevent file to be reloaded in other encoding after save with BOM - setCharsetWasDetectedFromBytes(virtualFile, true); - return; - } - - byte[] content = text.getBytes(charset); - CharsetToolkit.GuessedEncoding guessedEncoding = new CharsetToolkit(content).guessFromContent(content.length); - if (guessedEncoding == CharsetToolkit.GuessedEncoding.VALID_UTF8) { - setCharsetWasDetectedFromBytes(virtualFile, true); - } - } - - private static Charset chooseMostlyHarmlessCharset(Charset existing, Charset specified, String text) { - if (existing == null) return specified; - if (specified == null) return existing; - if (specified.equals(existing)) return specified; - if (isSupported(specified, text)) return specified; //if explicitly specified encoding is safe, return it - if (isSupported(existing, text)) return existing; //otherwise stick to the old encoding if it's ok - return specified; //if both are bad there is no difference - } - - private static boolean isSupported(@NotNull Charset charset, @NotNull String str) { - if (!charset.canEncode()) return false; - ByteBuffer out = charset.encode(str); - CharBuffer buffer = charset.decode(out); - return str.equals(buffer.toString()); - } - - public static Charset extractCharsetFromFileContent(@Nullable Project project, @NotNull VirtualFile virtualFile, @NotNull String text) { - Charset charset = charsetFromContentOrNull(project, virtualFile, text); - if (charset == null) charset = virtualFile.getCharset(); - return charset; - } - - @Nullable("returns null if cannot determine from content") - public static Charset charsetFromContentOrNull(@Nullable Project project, @NotNull VirtualFile virtualFile, @NotNull String text) { - FileType fileType = virtualFile.getFileType(); - if (fileType instanceof LanguageFileType) { - return ((LanguageFileType) fileType).extractCharsetFromFileContent(project, virtualFile, text); - } - return null; - } - - public static CharSequence loadText(@NotNull VirtualFile file) { - if (file instanceof LightVirtualFile) { - CharSequence content = ((LightVirtualFile) file).getContent(); - if (StringUtil.indexOf(content, '\r') == -1) return content; - - CharBuffer buffer = CharBuffer.allocate(content.length()); - buffer.append(content); - buffer.rewind(); - return convertLineSeparators(buffer).first; - } - - assert !file.isDirectory() : "'" + file.getPresentableUrl() + "' is directory"; - final FileType fileType = file.getFileType(); - - if (fileType.isBinary()) { - final BinaryFileDecompiler decompiler = BinaryFileTypeDecompilers.INSTANCE.forFileType(fileType); - if (decompiler != null) { - CharSequence text = decompiler.decompile(file); - StringUtil.assertValidSeparators(text); - return text; - } - - throw new IllegalArgumentException("Attempt to load text for binary file, that doesn't have decompiler plugged in: " + file.getPresentableUrl()); - } - - try { - byte[] bytes = file.contentsToByteArray(); - return getTextByBinaryPresentation(bytes, file); - } catch (IOException e) { - return ArrayUtil.EMPTY_CHAR_SEQUENCE; - } - } - - @NotNull - public static CharSequence getTextByBinaryPresentation(@NotNull final byte[] bytes, @NotNull VirtualFile virtualFile) { - return getTextByBinaryPresentation(bytes, virtualFile, true); - } - - @NotNull - public static CharSequence getTextByBinaryPresentation(@NotNull byte[] bytes, @NotNull VirtualFile virtualFile, final boolean rememberDetectedSeparators) { - Pair pair = doDetectCharsetAndSetBOM(virtualFile, bytes); - final Charset charset = pair.getFirst(); - byte[] bom = pair.getSecond(); - int offset = bom == null ? 0 : bom.length; - - final Pair result = convertBytes(bytes, charset, offset); - if (rememberDetectedSeparators) { - virtualFile.putUserData(DETECTED_LINE_SEPARATOR_KEY, result.getSecond()); - } - return result.getFirst(); - } - - /** - * Get detected line separator, if the file never been loaded, is loaded if checkFile parameter is specified. - * - * @param file the file to check - * @param checkFile if the line separator was not detected before, try to detect it - * @return the detected line separator or null - */ - @Nullable - public static String detectLineSeparator(@NotNull VirtualFile file, boolean checkFile) { - String lineSeparator = getDetectedLineSeparator(file); - if (lineSeparator == null && checkFile) { - try { - getTextByBinaryPresentation(file.contentsToByteArray(), file); - lineSeparator = getDetectedLineSeparator(file); - } catch (IOException e) { - // null will be returned - } - } - return lineSeparator; - } - - static String getDetectedLineSeparator(@NotNull VirtualFile file) { - return file.getUserData(DETECTED_LINE_SEPARATOR_KEY); - } - - /** - * Change line separator for the file to the specified value (assumes that the documents were saved) - * - * @param project the project instance - * @param requestor the requestor for the operation - * @param file the file to convert - * @param newLineSeparator the new line separator for the file - * @throws java.io.IOException in the case of IO problem - */ - public static void changeLineSeparator(@Nullable Project project, - @Nullable Object requestor, - @NotNull VirtualFile file, - @NotNull String newLineSeparator) throws IOException { - String lineSeparator = getDetectedLineSeparator(file); - if (lineSeparator != null && lineSeparator.equals(newLineSeparator)) { - return; - } - CharSequence cs = getTextByBinaryPresentation(file.contentsToByteArray(), file); - lineSeparator = getDetectedLineSeparator(file); - if (lineSeparator == null || lineSeparator.equals(newLineSeparator)) { - return; - } - if (!newLineSeparator.equals("\n")) { - cs = StringUtil.convertLineSeparators(cs.toString(), newLineSeparator); - } - String text = cs.toString(); - file.putUserData(DETECTED_LINE_SEPARATOR_KEY, newLineSeparator); - Writer w = getWriter(project, file, requestor, text, System.currentTimeMillis()); - try { - w.write(text); - } finally { - w.close(); - } - } - - @NotNull - public static CharSequence getTextByBinaryPresentation(@NotNull byte[] bytes, Charset charset) { - Pair pair = getBOMAndCharset(bytes, charset); - byte[] bom = pair.getSecond(); - int offset = bom == null ? 0 : bom.length; - - final Pair result = convertBytes(bytes, charset, offset); - return result.getFirst(); - } - - // do not need to think about BOM here. it is processed outside - @NotNull - private static Pair convertBytes(@NotNull byte[] bytes, Charset charset, final int startOffset) { - ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, startOffset, bytes.length - startOffset); - - if (charset == null) { - charset = CharsetToolkit.getDefaultSystemCharset(); - } - if (charset == null) { - //noinspection HardCodedStringLiteral - charset = Charset.forName("ISO-8859-1"); - } - CharBuffer charBuffer = charset.decode(byteBuffer); - return convertLineSeparators(charBuffer); - } - - private static final Key CHARSET_WAS_DETECTED_FROM_BYTES = new Key("CHARSET_WAS_DETECTED_FROM_BYTES"); - - public static boolean wasCharsetDetectedFromBytes(@NotNull VirtualFile virtualFile) { - return virtualFile.getUserData(CHARSET_WAS_DETECTED_FROM_BYTES) != null; - } - - public static void setCharsetWasDetectedFromBytes(@NotNull VirtualFile virtualFile, boolean flag) { - virtualFile.putUserData(CHARSET_WAS_DETECTED_FROM_BYTES, flag ? Boolean.TRUE : null); - } -} diff --git a/idea_fix/src/com/intellij/openapi/util/IconLoader.java b/idea_fix/src/com/intellij/openapi/util/IconLoader.java deleted file mode 100644 index 70c739fed80..00000000000 --- a/idea_fix/src/com/intellij/openapi/util/IconLoader.java +++ /dev/null @@ -1,351 +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.openapi.util; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.reference.SoftReference; -import com.intellij.util.ImageLoader; -import com.intellij.util.containers.ConcurrentHashMap; -import com.intellij.util.containers.WeakHashMap; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.lang.ref.Reference; -import java.net.URL; -import java.util.Map; - -//import sun.reflect.Reflection; - -public final class IconLoader { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.IconLoader"); - - @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - private static final ConcurrentHashMap ourIconsCache = new ConcurrentHashMap(100, 0.9f, 2); - - /** - * This cache contains mapping between icons and disabled icons. - */ - private static final Map ourIcon2DisabledIcon = new WeakHashMap(200); - - private static final ImageIcon EMPTY_ICON = new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR)) { - @NonNls - public String toString() { - return "Empty icon " + super.toString(); - } - }; - - private static boolean ourIsActivated = false; - - private IconLoader() { - } - - @Deprecated - public static Icon getIcon(@NotNull final Image image) { - return new MyImageIcon(image); - } - - @NotNull - public static Icon getIcon(@NonNls final String path) { - int stackFrameCount = 2; - return IconLoader.EMPTY_ICON; - /*Class callerClass = Reflection.getCallerClass(stackFrameCount); - while (callerClass != null && callerClass.getClassLoader() == null) { // looks like a system class - callerClass = Reflection.getCallerClass(++stackFrameCount); - } - if (callerClass == null) { - callerClass = Reflection.getCallerClass(1); - } - return getIcon(path, callerClass);*/ - } - - @Nullable - /** - * Might return null if icon was not found. - * Use only if you expected null return value, otherwise see {@link com.intellij.openapi.util.IconLoader#getIcon(String)} - */ - public static Icon findIcon(@NonNls final String path) { - int stackFrameCount = 2; - return IconLoader.EMPTY_ICON; - /*Class callerClass = Reflection.getCallerClass(stackFrameCount); - while (callerClass != null && callerClass.getClassLoader() == null) { // looks like a system class - callerClass = Reflection.getCallerClass(++stackFrameCount); - } - if (callerClass == null) { - callerClass = Reflection.getCallerClass(1); - } - return findIcon(path, callerClass);*/ - } - - @NotNull - public static Icon getIcon(@NotNull String path, @NotNull final Class aClass) { - final Icon icon = findIcon(path, aClass); - if (icon == null) { - LOG.error("Icon cannot be found in '" + path + "', aClass='" + aClass + "'"); - } - return icon; - } - - public static void activate() { - ourIsActivated = true; - } - - private static boolean isLoaderDisabled() { - return !ourIsActivated; - } - - /** - * Might return null if icon was not found. - * Use only if you expected null return value, otherwise see {@link com.intellij.openapi.util.IconLoader#getIcon(String, Class)} - */ - @Nullable - public static Icon findIcon(@NotNull final String path, @NotNull final Class aClass) { - return findIcon(path, aClass, false); - } - - public static Icon findIcon(@NotNull final String path, @NotNull final Class aClass, boolean computeNow) { - /*final ByClass icon = new ByClass(aClass, path); - - if (computeNow || !Registry.is("ide.lazyIconLoading", true)) { - return icon.getOrComputeIcon(); - } - - return icon;*/ - return IconLoader.EMPTY_ICON; - } - - @Nullable - private static Icon findIcon(URL url) { - if (url == null) return null; - Icon icon = ourIconsCache.get(url); - if (icon == null) { - icon = new CachedImageIcon(url); - icon = ourIconsCache.cacheOrGet(url, icon); - } - return icon; - } - - @Nullable - public static Icon findIcon(final String path, final ClassLoader aClassLoader) { - if (!path.startsWith("/")) return null; - - final URL url = aClassLoader.getResource(path.substring(1)); - return findIcon(url); - } - - @Nullable - private static Icon checkIcon(final Image image, URL url) { - if (image == null || image.getHeight(LabelHolder.ourFakeComponent) < 1) { // image wasn't loaded or broken - return null; - } - - final Icon icon = getIcon(image); - if (icon != null && !isGoodSize(icon)) { - LOG.error("Invalid icon: " + url); // # 22481 - return EMPTY_ICON; - } - return icon; - } - - public static boolean isGoodSize(@NotNull final Icon icon) { - return icon.getIconWidth() > 0 && icon.getIconHeight() > 0; - } - - /** - * Gets (creates if necessary) disabled icon based on the passed one. - * - * @param icon - * @return ImageIcon constructed from disabled image of passed icon. - */ - @Nullable - public static Icon getDisabledIcon(final Icon icon) { - if (icon == null) { - return null; - } - Icon disabledIcon = ourIcon2DisabledIcon.get(icon); - if (disabledIcon == null) { - if (!isGoodSize(icon)) { - LOG.error(icon); // # 22481 - return EMPTY_ICON; - } - final BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB); - final Graphics2D graphics = image.createGraphics(); - - graphics.setColor(UIUtil.TRANSPARENT_COLOR); - graphics.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight()); - icon.paintIcon(LabelHolder.ourFakeComponent, graphics, 0, 0); - - graphics.dispose(); - - disabledIcon = new MyImageIcon(GrayFilter.createDisabledImage(image)); - ourIcon2DisabledIcon.put(icon, disabledIcon); - } - return disabledIcon; - } - - public static Icon getTransparentIcon(final Icon icon) { - return getTransparentIcon(icon, 0.5f); - } - - public static Icon getTransparentIcon(final Icon icon, final float alpha) { - return new Icon() { - public int getIconHeight() { - return icon.getIconHeight(); - } - - public int getIconWidth() { - return icon.getIconWidth(); - } - - public void paintIcon(final Component c, final Graphics g, final int x, final int y) { - final Graphics2D g2 = (Graphics2D) g; - final Composite saveComposite = g2.getComposite(); - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); - icon.paintIcon(c, g2, x, y); - g2.setComposite(saveComposite); - } - }; - } - - private static final class CachedImageIcon implements Icon { - private Object myRealIcon; - private final URL myUrl; - - public CachedImageIcon(URL url) { - myUrl = url; - } - - private synchronized Icon getRealIcon() { - if (isLoaderDisabled()) return EMPTY_ICON; - - if (myRealIcon instanceof Icon) return (Icon) myRealIcon; - - Icon icon; - if (myRealIcon instanceof Reference) { - icon = ((Reference) myRealIcon).get(); - if (icon != null) return icon; - } - - Image image = ImageLoader.loadFromUrl(myUrl); - icon = checkIcon(image, myUrl); - - if (icon != null) { - if (icon.getIconWidth() < 50 && icon.getIconHeight() < 50) { - myRealIcon = icon; - } else { - myRealIcon = new SoftReference(icon); - } - } - - return icon != null ? icon : EMPTY_ICON; - } - - public void paintIcon(Component c, Graphics g, int x, int y) { - getRealIcon().paintIcon(c, g, x, y); - } - - public int getIconWidth() { - return getRealIcon().getIconWidth(); - } - - public int getIconHeight() { - return getRealIcon().getIconHeight(); - } - } - - private static final class MyImageIcon extends ImageIcon { - public MyImageIcon(final Image image) { - super(image); - } - - public final synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) { - super.paintIcon(null, g, x, y); - } - } - - public abstract static class LazyIcon implements Icon { - private boolean myWasComputed; - private Icon myIcon; - - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - final Icon icon = getOrComputeIcon(); - if (icon != null) { - icon.paintIcon(c, g, x, y); - } - } - - @Override - public int getIconWidth() { - final Icon icon = getOrComputeIcon(); - return icon != null ? icon.getIconWidth() : 0; - } - - @Override - public int getIconHeight() { - final Icon icon = getOrComputeIcon(); - return icon != null ? icon.getIconHeight() : 0; - } - - protected synchronized final Icon getOrComputeIcon() { - if (!myWasComputed) { - myWasComputed = true; - myIcon = compute(); - } - - return myIcon; - } - - public final void load() { - getIconWidth(); - } - - protected abstract Icon compute(); - } - - private static class ByClass extends LazyIcon { - private final Class myCallerClass; - private final String myPath; - - public ByClass(Class aClass, String path) { - myCallerClass = aClass; - myPath = path; - } - - @Override - protected Icon compute() { - URL url = myCallerClass.getResource(myPath); - return findIcon(url); - } - - @Override - public String toString() { - return "icon path=" + myPath + " class=" + myCallerClass; - } - } - - private static class LabelHolder { - /** - * To get disabled icon with paint it into the image. Some icons require - * not null component to paint. - */ - private static final JComponent ourFakeComponent = new JLabel(); - } -} diff --git a/idea_fix/src/com/intellij/openapi/util/UserDataHolderBase.java b/idea_fix/src/com/intellij/openapi/util/UserDataHolderBase.java deleted file mode 100644 index 7c7b4fa3c56..00000000000 --- a/idea_fix/src/com/intellij/openapi/util/UserDataHolderBase.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2000-2009 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.util; - - -//import com.intellij.util.concurrency.AtomicFieldUpdater; - -import com.intellij.util.containers.StripedLockConcurrentHashMap; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; - -import java.util.ConcurrentModificationException; -import java.util.Map; -import java.util.concurrent.ConcurrentMap; - -public class UserDataHolderBase implements UserDataHolderEx, Cloneable { - private static final Key> COPYABLE_USER_MAP_KEY = Key.create("COPYABLE_USER_MAP_KEY"); - - /** - * Concurrent writes to this field are via CASes only, using the {@link #} - * When map becomes empty, this field set to null atomically - *

- * Basic state transitions are as follows: - *

- * (adding keyvalue) (putUserData(key,value)) - * [myUserMap=null] -> [myUserMap=(key->value)] - *

- * (adding another) (putUserData(key2,value2)) - * [myUserMap=(key->value)] -> [myUserMap=(key->value, key2->value2)] - *

- * (removing keyvalue) (putUserData(k2,null)) - * [myUserMap=(key->value, k2->v2)] -> [myUserMap=(key->value)] - *

- * (removing last entry) (putUserData(key,null)) - * [myUserMap=(key->value)] -> [myUserMap=null] - */ - private volatile ConcurrentMap myUserMap = null; - - protected Object clone() { - try { - UserDataHolderBase clone = (UserDataHolderBase) super.clone(); - clone.myUserMap = null; - copyCopyableDataTo(clone); - return clone; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - - } - } - - @TestOnly - public String getUserDataString() { - final ConcurrentMap userMap = myUserMap; - if (userMap == null) { - return ""; - } - final Map copyableMap = getUserData(COPYABLE_USER_MAP_KEY); - return userMap.toString() + (copyableMap == null ? "" : copyableMap.toString()); - } - - public void copyUserDataTo(UserDataHolderBase other) { - ConcurrentMap map = myUserMap; - if (map == null) { - other.myUserMap = null; - } else { - ConcurrentMap fresh = createDataMap(map.size()); - fresh.putAll(map); - other.myUserMap = fresh; - } - } - - public T getUserData(@NotNull Key key) { - final Map map = myUserMap; - //noinspection unchecked - return map == null ? null : (T) map.get(key); - } - - public void putUserData(@NotNull Key key, @Nullable T value) { - while (true) { - try { - if (value == null) { - ConcurrentMap map = myUserMap; - if (map == null) break; - @SuppressWarnings("unchecked") - T previous = (T) map.remove(key); - boolean removed = previous != null; - if (removed) { - nullifyMapFieldIfEmpty(); - } - } else { - getOrCreateMap().put(key, value); - } - break; - } catch (ConcurrentModificationException ignored) { - } - } - } - - private static ConcurrentMap createDataMap(int initialCapacity) { - return new StripedLockConcurrentHashMap(initialCapacity); - } - - public T getCopyableUserData(Key key) { - return getCopyableUserDataImpl(key); - } - - protected final T getCopyableUserDataImpl(Key key) { - Map map = getUserData(COPYABLE_USER_MAP_KEY); - //noinspection unchecked - return map == null ? null : (T) map.get(key); - } - - public void putCopyableUserData(Key key, T value) { - putCopyableUserDataImpl(key, value); - } - - private Map getOrCreateCopyableMap(boolean create) { - Map copyMap = getUserData(COPYABLE_USER_MAP_KEY); - if (copyMap == null && create) { - copyMap = createDataMap(1); - copyMap = putUserDataIfAbsent(COPYABLE_USER_MAP_KEY, copyMap); - } - - return copyMap; - } - - protected final void putCopyableUserDataImpl(Key key, T value) { - while (true) { - try { - Map copyMap = getOrCreateCopyableMap(value != null); - if (copyMap == null) break; - - if (value == null) { - copyMap.remove(key); - if (copyMap.isEmpty()) { - ((StripedLockConcurrentHashMap) copyMap).blockModification(); - ConcurrentMap newCopyMap; - if (copyMap.isEmpty()) { - newCopyMap = null; - } else { - newCopyMap = createDataMap(copyMap.size()); - newCopyMap.putAll(copyMap); - } - boolean replaced = replace(COPYABLE_USER_MAP_KEY, copyMap, newCopyMap); - if (!replaced) continue; - } - } else { - copyMap.put(key, value); - } - break; - } catch (ConcurrentModificationException ignored) { - // someone blocked modification, retry - } - } - } - - private ConcurrentMap getOrCreateMap() { - while (true) { - ConcurrentMap map = myUserMap; - if (map != null) return map; - map = createDataMap(2); - boolean updated = true; - //throw new UnsupportedOperationException("Exception in (my) UserDataHolderBase"); -// boolean updated = updater.compareAndSet(this, null, map); - if (updated) { - return map; - } - } - } - - public boolean replace(@NotNull Key key, @Nullable T oldValue, @Nullable T newValue) { - while (true) { - try { - ConcurrentMap map = getOrCreateMap(); - if (oldValue == null) { - return newValue == null || map.putIfAbsent(key, newValue) == null; - } - if (newValue == null) { - boolean removed = map.remove(key, oldValue); - if (removed) { - nullifyMapFieldIfEmpty(); - } - return removed; - } - return map.replace(key, oldValue, newValue); - } catch (ConcurrentModificationException ignored) { - // someone blocked modification, retry - } - } - } - - @NotNull - public T putUserDataIfAbsent(@NotNull final Key key, @NotNull final T value) { - Object v = getOrCreateMap().get(key); - if (v != null) { - //noinspection unchecked - return (T) v; - } - while (true) { - try { - @SuppressWarnings("unchecked") - T prev = (T) getOrCreateMap().putIfAbsent(key, value); - return prev == null ? value : prev; - } catch (ConcurrentModificationException ignored) { - // someone blocked modification, retry - } - } - } - - public void copyCopyableDataTo(@NotNull UserDataHolderBase clone) { - Map copyableMap = getUserData(COPYABLE_USER_MAP_KEY); - if (copyableMap != null) { - ConcurrentMap copy = createDataMap(copyableMap.size()); - copy.putAll(copyableMap); - copyableMap = copy; - } - clone.putUserData(COPYABLE_USER_MAP_KEY, copyableMap); - } - - protected void clearUserData() { - myUserMap = null; - } - -// private static final AtomicFieldUpdater updater = AtomicFieldUpdater.forFieldOfType(UserDataHolderBase.class, ConcurrentMap.class); - - private void nullifyMapFieldIfEmpty() { - try { - while (true) { - StripedLockConcurrentHashMap map = (StripedLockConcurrentHashMap) myUserMap; - if (map == null || !map.isEmpty()) break; - map.blockModification(); // we block the map and either replace it with null or fail with replace, in both cases the map is thrown away - ConcurrentMap newMap; - if (map.isEmpty()) { - newMap = null; - } else { - // someone managed to add something in the meantime - // atomically replace the blocked map with newly created map filled with the data sneaked in - newMap = createDataMap(map.size()); - newMap.putAll(map); - } - boolean replaced = true; - //throw new UnsupportedOperationException("Exception in (my) UserDataHolderBase"); - //boolean replaced = updater.compareAndSet(this, map, newMap); - if (replaced) break; - // else someone has replaced map already and pushing back the changes is his responsibility - } - } catch (ConcurrentModificationException ignored) { - // somebody has already blocked the map, back off - } - } -} diff --git a/idea_fix/src/com/intellij/openapi/vfs/impl/jar/CoreJarHandler.java b/idea_fix/src/com/intellij/openapi/vfs/impl/jar/CoreJarHandler.java deleted file mode 100644 index 3362a67f7be..00000000000 --- a/idea_fix/src/com/intellij/openapi/vfs/impl/jar/CoreJarHandler.java +++ /dev/null @@ -1,54 +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.openapi.vfs.impl.jar; - -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author yole - */ -public class CoreJarHandler extends JarHandlerBase { - private final Map myFileMap = new HashMap(); - private final CoreJarFileSystem myFileSystem; - - public CoreJarHandler(CoreJarFileSystem fileSystem, String path) { - super(fileSystem, path); - myFileSystem = fileSystem; - } - - @Nullable - public VirtualFile findFileByPath(String pathInJar) { - if (getZip() == null) { - return null; - } - VirtualFile file = myFileMap.get(pathInJar); - if (file == null) { - if (pathInJar.length() > 0) { - EntryInfo entryInfo = getEntryInfo(pathInJar); - if (entryInfo == null) { - return null; - } - } - file = new CoreJarVirtualFile(myFileSystem, this, pathInJar); - myFileMap.put(pathInJar, file); - } - return file; - } -} diff --git a/idea_fix/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java b/idea_fix/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java deleted file mode 100644 index d87e1d322d5..00000000000 --- a/idea_fix/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java +++ /dev/null @@ -1,266 +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.openapi.vfs.impl.jar; - -import com.intellij.openapi.util.io.BufferExposingByteArrayInputStream; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ArrayUtil; -import com.intellij.util.TimedReference; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.lang.ref.SoftReference; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -public class JarHandlerBase { - protected final TimedReference myZipFile = new TimedReference(null); - protected SoftReference> myRelPathsToEntries = new SoftReference>(null); - protected final Object lock = new Object(); - private InputStream inputStream; - - protected final String myBasePath; - - protected static class EntryInfo { - public EntryInfo(final String shortName, final EntryInfo parent, final boolean directory, byte[] content) { - this.shortName = new String(shortName); - this.parent = parent; - isDirectory = directory; - this.content = content; - - } - - final boolean isDirectory; - final byte[] content; - protected final String shortName; - final EntryInfo parent; - } - - public JarHandlerBase(CoreJarFileSystem myFileSystem, String path) { - if (inputStream == null) { - try { - inputStream = new VirtualJarFile(myFileSystem, path).getInputStream(); - } catch (IOException e) { - e.printStackTrace(); - } - } - myBasePath = path; - } - - @NotNull - protected Map initEntries() { - synchronized (lock) { - Map map = myRelPathsToEntries.get(); - if (map == null) { - final ZipInputStream zip = getZip(); - - map = new HashMap(); - if (zip != null) { - map.put("", new EntryInfo("", null, true, new byte[0])); - try { - ZipEntry entry = zip.getNextEntry(); - while (entry != null) { - final String name = entry.getName(); - final boolean isDirectory = name.endsWith("/"); - if (entry.getExtra() == null) { - byte[] cont = new byte[(int) entry.getSize()]; - ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); - InputStream stream = getZip(); - if (stream != null) { - int tmp; - if ((tmp = stream.read(cont)) == entry.getSize()) { - byteArray.write(cont, 0, tmp); - entry.setExtra(byteArray.toByteArray()); - } else { - int readFromIS = tmp; - if (tmp < entry.getSize()) { - byteArray.write(cont, 0, tmp); - while (((tmp = stream.read(cont)) != -1) && (tmp + readFromIS <= entry.getSize())) { - byteArray.write(cont, 0, tmp); - readFromIS += tmp; - } - entry.setExtra(byteArray.toByteArray()); - } - } - } - } - getOrCreate(isDirectory ? name.substring(0, name.length() - 1) : name, isDirectory, map, entry.getExtra()); - - entry = zip.getNextEntry(); - } - } catch (IOException e) { - e.printStackTrace(); - } - myRelPathsToEntries = new SoftReference>(map); - } - } - return map; - } - } - - public File getMirrorFile(File originalFile) { - return originalFile; - } - - @Nullable - public ZipInputStream getZip() { - ZipInputStream zip = myZipFile.get(); - if (zip == null) { - if (inputStream == null) { - throw new IllegalArgumentException("Input Stream is null"); - } else { - zip = new ZipInputStream(inputStream); - } - myZipFile.set(zip); - } - return zip; - } - - protected InputStream getOriginalFile() { - - return inputStream; - } - - private static EntryInfo getOrCreate(String entryName, boolean isDirectory, Map map, byte[] content) { - EntryInfo info = map.get(entryName); - if (info == null) { - int idx = entryName.lastIndexOf('/'); - final String parentEntryName = idx > 0 ? entryName.substring(0, idx) : ""; - String shortName = idx > 0 ? entryName.substring(idx + 1) : entryName; - if (".".equals(shortName)) return getOrCreate(parentEntryName, true, map, content); - - info = new EntryInfo(shortName, getOrCreate(parentEntryName, true, map, content), isDirectory, content); - map.put(entryName, info); - } - - return info; - } - - @NotNull - public String[] list(@NotNull final VirtualFile file) { - synchronized (lock) { - EntryInfo parentEntry = getEntryInfo(file); - - Set names = new HashSet(); - for (EntryInfo info : getEntriesMap().values()) { - if (info.parent == parentEntry) { - names.add(info.shortName); - } - } - - return ArrayUtil.toStringArray(names); - } - } - - protected EntryInfo getEntryInfo(final VirtualFile file) { - synchronized (lock) { - String parentPath = getRelativePath(file); - return getEntryInfo(parentPath); - } - } - - public EntryInfo getEntryInfo(String parentPath) { - return getEntriesMap().get(parentPath); - } - - protected Map getEntriesMap() { - return initEntries(); - } - - private String getRelativePath(final VirtualFile file) { -// throw new UnsupportedOperationException(file.getPath()); - final String path = file.getPath().substring(myBasePath.length() + 1); - return path.startsWith("/") ? path.substring(1) : path; - } - - @Nullable - private ZipEntry convertToEntry(VirtualFile file) { - String path = getRelativePath(file); - final ZipInputStream zip = getZip(); - return null; - } - - @Nullable - private EntryInfo convertToISEntry(VirtualFile file) { - String path = getRelativePath(file); - final ZipInputStream zip = getZip(); - return myRelPathsToEntries.get().get(path); - } - - public long getLength(@NotNull final VirtualFile file) { - synchronized (lock) { - final ZipEntry entry = convertToEntry(file); - return entry != null ? entry.getSize() : 0; - } - } - - @NotNull - public InputStream getInputStream(@NotNull final VirtualFile file) throws IOException { - return new BufferExposingByteArrayInputStream(contentsToByteArray(file)); - } - - @NotNull - public byte[] contentsToByteArray(@NotNull final VirtualFile file) throws IOException { - synchronized (lock) { - EntryInfo info = convertToISEntry(file); - if (info == null) { - return new byte[0]; - } - byte[] content = info.content; - if (content == null) { - return new byte[0]; - } - return content; - - } - } - - public long getTimeStamp(@NotNull final VirtualFile file) { - if (file.getParent() == null) return file.getTimeStamp(); // Optimization -// if (file.getParent() == null) return getOriginalFile().lastModified(); // Optimization - synchronized (lock) { - final ZipEntry entry = convertToEntry(file); - return entry != null ? entry.getTime() : -1L; - } - } - - public boolean isDirectory(@NotNull final VirtualFile file) { - if (file.getParent() == null) return true; // Optimization - synchronized (lock) { - final String path = getRelativePath(file); - final EntryInfo info = getEntryInfo(path); - return info == null || info.isDirectory; - } - } - - public boolean exists(@NotNull final VirtualFile fileOrDirectory) { - if (fileOrDirectory.getParent() == null) { - // Optimization. Do not build entries if asked for jar root existence. - return myZipFile.get() != null; -// return myZipFile.get() != null || getOriginalFile().exists(); - } - - return getEntryInfo(fileOrDirectory) != null; - } -} diff --git a/idea_fix/src/com/intellij/openapi/vfs/impl/jar/VirtualJarFile.java b/idea_fix/src/com/intellij/openapi/vfs/impl/jar/VirtualJarFile.java deleted file mode 100644 index 4021bb413f1..00000000000 --- a/idea_fix/src/com/intellij/openapi/vfs/impl/jar/VirtualJarFile.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.intellij.openapi.vfs.impl.jar; - -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileSystem; -import org.jetbrains.annotations.NotNull; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Created by IntelliJ IDEA. - * User: Natalia.Ukhorskaya - * Date: 12/1/11 - * Time: 5:06 PM - */ - -public class VirtualJarFile extends VirtualFile { - private byte[] byteArray; - private final CoreJarFileSystem myFileSystem; - private final String name; - - public VirtualJarFile(CoreJarFileSystem myFileSystem, String pathInJar) { - this.myFileSystem = myFileSystem; - this.name = pathInJar; - } - - @NotNull - @Override - public String getName() { - return name; - } - - @NotNull - @Override - public VirtualFileSystem getFileSystem() { - return myFileSystem; - } - - @Override - public String getPath() { - return name; - } - - @Override - public boolean isWritable() { - return false; - } - - @Override - public boolean isDirectory() { - return false; - } - - @Override - public boolean isValid() { - return true; - } - - @Override - public VirtualFile getParent() { - return null; - } - - @Override - public VirtualFile[] getChildren() { - return VirtualFile.EMPTY_ARRAY; - } - - @NotNull - @Override - public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) throws IOException { - return System.out; - } - - @NotNull - @Override - public byte[] contentsToByteArray() throws IOException { - if (byteArray.length <= 0) { - int length; - byte[] tmp = new byte[1024]; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - InputStream rtJar = VirtualJarFile.class.getResourceAsStream("/" + name); - try { - while ((length = rtJar.read(tmp)) >= 0) { - out.write(tmp, 0, length); - } - } catch (IOException e) { - e.printStackTrace(); - return new byte[0]; - } - byteArray = out.toByteArray(); - } - return byteArray; - } - - @Override - public long getTimeStamp() { - return 0; - } - - @Override - public long getLength() { - return byteArray.length; - } - - @Override - public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) { - - } - - @Override - public InputStream getInputStream() throws IOException { - return VirtualJarFile.class.getResourceAsStream("/" + name); - } -} diff --git a/idea_fix/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConstants.java b/idea_fix/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConstants.java deleted file mode 100644 index da2c8391363..00000000000 --- a/idea_fix/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConstants.java +++ /dev/null @@ -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.openapi.vfs.newvfs.persistent; - -public class PersistentFSConstants { - public static final long FILE_LENGTH_TO_CACHE_THRESHOLD = 20 * 1024 * 1024; // 20 megabytes - /** - * always in range [0, PersistentFS.FILE_LENGTH_TO_CACHE_THRESHOLD] - */ - public static final int MAX_INTELLISENSE_FILESIZE = maxIntellisenseFileSize(); -// @NonNls private static final String MAX_INTELLISENSE_SIZE_PROPERTY = "idea.max.intellisense.filesize"; - - private PersistentFSConstants() { - } - - private static int maxIntellisenseFileSize() { - final int maxLimitBytes = (int) FILE_LENGTH_TO_CACHE_THRESHOLD; - final String userLimitKb = "100"; -// final String userLimitKb = System.getProperty(MAX_INTELLISENSE_SIZE_PROPERTY); - try { - return userLimitKb != null ? Math.min(Integer.parseInt(userLimitKb) * 1024, maxLimitBytes) : maxLimitBytes; - } catch (NumberFormatException ignored) { - return maxLimitBytes; - } - } -} diff --git a/idea_fix/src/com/intellij/psi/SingleRootFileViewProvider.java b/idea_fix/src/com/intellij/psi/SingleRootFileViewProvider.java deleted file mode 100644 index 64f2802d665..00000000000 --- a/idea_fix/src/com/intellij/psi/SingleRootFileViewProvider.java +++ /dev/null @@ -1,535 +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 com.intellij.lang.Language; -import com.intellij.lang.LanguageParserDefinitions; -import com.intellij.lang.ParserDefinition; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.undo.UndoConstants; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.file.exclude.ProjectFileExclusionManager; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.impl.LoadTextUtil; -import com.intellij.openapi.fileTypes.*; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.openapi.vfs.NonPhysicalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSConstants; -import com.intellij.psi.impl.PsiFileEx; -import com.intellij.psi.impl.PsiManagerEx; -import com.intellij.psi.impl.PsiManagerImpl; -import com.intellij.psi.impl.compiled.ClsFileImpl; -import com.intellij.psi.impl.file.PsiBinaryFileImpl; -import com.intellij.psi.impl.source.PsiFileImpl; -import com.intellij.psi.impl.source.PsiPlainTextFileImpl; -import com.intellij.psi.impl.source.tree.FileElement; -import com.intellij.testFramework.LightVirtualFile; -import com.intellij.util.LocalTimeCounter; -import com.intellij.util.ReflectionCache; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.ref.SoftReference; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; - -public class SingleRootFileViewProvider extends UserDataHolderBase implements FileViewProvider { - private static final Key OUR_NO_SIZE_LIMIT_KEY = Key.create("no.size.limit"); - private static final Logger LOG = Logger.getInstance("#" + SingleRootFileViewProvider.class.getCanonicalName()); - private final PsiManager myManager; - private final VirtualFile myVirtualFile; - private final boolean myEventSystemEnabled; - private final boolean myPhysical; - private final AtomicReference myPsiFile = new AtomicReference(); - private volatile Content myContent; - private volatile SoftReference myDocument; - private final Language myBaseLanguage; - private final ProjectFileExclusionManager myExclusionManager; - - public SingleRootFileViewProvider(@NotNull PsiManager manager, @NotNull VirtualFile file) { - this(manager, file, true); - } - - public SingleRootFileViewProvider(@NotNull PsiManager manager, @NotNull VirtualFile virtualFile, final boolean physical) { - this(manager, virtualFile, physical, calcBaseLanguage(virtualFile, manager.getProject())); - } - - protected SingleRootFileViewProvider(@NotNull PsiManager manager, @NotNull VirtualFile virtualFile, final boolean physical, @NotNull Language language) { - myManager = manager; - myVirtualFile = virtualFile; - myEventSystemEnabled = physical; - myBaseLanguage = language; - setContent(new VirtualFileContent()); - myPhysical = isEventSystemEnabled() && - !(virtualFile instanceof LightVirtualFile) && - !(virtualFile.getFileSystem() instanceof NonPhysicalFileSystem); - myExclusionManager = ProjectFileExclusionManager.SERVICE.getInstance(manager.getProject()); - } - - @Override - @NotNull - public Language getBaseLanguage() { - return myBaseLanguage; - } - - private static Language calcBaseLanguage(@NotNull VirtualFile file, @NotNull Project project) { - if (file instanceof LightVirtualFile) { - final Language language = ((LightVirtualFile) file).getLanguage(); - if (language != null) { - return language; - } - } - - FileType fileType = file.getFileType(); - // Do not load content - if (fileType == UnknownFileType.INSTANCE) { - fileType = FileTypeRegistry.getInstance().detectFileTypeFromContent(file); - } - if (fileType.isBinary()) return Language.ANY; - if (isTooLarge(file)) return PlainTextLanguage.INSTANCE; - - if (fileType instanceof LanguageFileType) { - return LanguageSubstitutors.INSTANCE.substituteLanguage(((LanguageFileType) fileType).getLanguage(), file, project); - } - - final ContentBasedFileSubstitutor[] processors = Extensions.getExtensions(ContentBasedFileSubstitutor.EP_NAME); - for (ContentBasedFileSubstitutor processor : processors) { - Language language = processor.obtainLanguageForFile(file); - if (language != null) return language; - } - - return PlainTextLanguage.INSTANCE; - } - - @Override - @NotNull - public Set getLanguages() { - return Collections.singleton(getBaseLanguage()); - } - - @Override - @Nullable - public final PsiFile getPsi(@NotNull Language target) { - /*if (!isPhysical()) { - ((PsiManagerEx) myManager).getFileManager().setViewProvider(getVirtualFile(), this); - }*/ - return getPsiInner(target); - } - - @Override - @NotNull - public List getAllFiles() { - return Collections.singletonList(getPsi(getBaseLanguage())); - } - - @Nullable - protected PsiFile getPsiInner(final Language target) { - if (target != getBaseLanguage()) { - return null; - } - PsiFile psiFile = myPsiFile.get(); - if (psiFile == null) { - psiFile = createFile(); - boolean set = myPsiFile.compareAndSet(null, psiFile); - if (!set) { - psiFile = myPsiFile.get(); - } - } - return psiFile; - } - - @Override - public void beforeContentsSynchronized() { - unsetPsiContent(); - } - - @Override - public void contentsSynchronized() { - unsetPsiContent(); - } - - private void unsetPsiContent() { - if (!(myContent instanceof PsiFileContent)) return; - final Document cachedDocument = getCachedDocument(); - setContent(cachedDocument == null ? new VirtualFileContent() : new DocumentContent()); - } - - public void beforeDocumentChanged() { - final PsiFileImpl psiFile = (PsiFileImpl) getCachedPsi(getBaseLanguage()); - if (psiFile != null && psiFile.isContentsLoaded() && getContent() instanceof DocumentContent) { - setContent(new PsiFileContent(psiFile, getModificationStamp())); - } - } - - @Override - public void rootChanged(PsiFile psiFile) { - if (((PsiFileEx) psiFile).isContentsLoaded()) { - setContent(new PsiFileContent((PsiFileImpl) psiFile, LocalTimeCounter.currentTime())); - } - } - - @Override - public boolean isEventSystemEnabled() { - return myEventSystemEnabled; - } - - @Override - public boolean isPhysical() { - return myPhysical; - } - - @Override - public long getModificationStamp() { - return getContent().getModificationStamp(); - } - - @Override - public boolean supportsIncrementalReparse(final Language rootLanguage) { - return true; - } - - - public PsiFile getCachedPsi(Language target) { - return myPsiFile.get(); - } - - public FileElement[] getKnownTreeRoots() { - PsiFile psiFile = myPsiFile.get(); - if (psiFile == null || !(psiFile instanceof PsiFileImpl)) return new FileElement[0]; - if (((PsiFileImpl) psiFile).getTreeElement() == null) return new FileElement[0]; - return new FileElement[]{(FileElement) psiFile.getNode()}; - } - - private PsiFile createFile() { - try { - final VirtualFile vFile = getVirtualFile(); - if (vFile.isDirectory()) return null; - if (isIgnored()) return null; - - final Project project = myManager.getProject(); - if (isPhysical()) { // check directories consistency - final VirtualFile parent = vFile.getParent(); - if (parent == null) return null; - final PsiDirectory psiDir = getManager().findDirectory(parent); - if (psiDir == null) return null; - } - - FileType fileType = vFile.getFileType(); - PsiFile file = null; - if (fileType.isBinary() || vFile.isSpecialFile()) { - //TODO check why ClsFileImpl doesn't created automatically with create method - file = new ClsFileImpl((PsiManagerImpl) getManager(), this); - //file = new PsiBinaryFileImpl((PsiManagerImpl) getManager(), this); - } else { - if (!isTooLarge(vFile)) { - final PsiFile psiFile = createFile(getBaseLanguage()); - if (psiFile != null) file = psiFile; - } else { - file = new PsiPlainTextFileImpl(this); - } - } - return file; - } catch (ProcessCanceledException e) { - e.printStackTrace(); - throw e; - - } catch (Throwable e) { - e.printStackTrace(); - LOG.error(e); - return null; - } - } - - protected boolean isIgnored() { - final VirtualFile file = getVirtualFile(); - if (file instanceof LightVirtualFile) return false; - if (myExclusionManager != null && myExclusionManager.isExcluded(file)) return true; - return FileTypeRegistry.getInstance().isFileIgnored(file); - } - - @Nullable - protected PsiFile createFile(@NotNull Project project, @NotNull VirtualFile file, @NotNull FileType fileType) { - if (fileType.isBinary() || file.isSpecialFile()) { - return new PsiBinaryFileImpl((PsiManagerImpl) getManager(), this); - } - if (!isTooLarge(file)) { - final PsiFile psiFile = createFile(getBaseLanguage()); - if (psiFile != null) return psiFile; - } - - return new PsiPlainTextFileImpl(this); - } - - public static boolean isTooLarge(@NotNull VirtualFile vFile) { - if (!checkFileSizeLimit(vFile)) return false; - return fileSizeIsGreaterThan(vFile, PersistentFSConstants.MAX_INTELLISENSE_FILESIZE); - } - - private static boolean checkFileSizeLimit(@NotNull VirtualFile vFile) { - return !Boolean.TRUE.equals(vFile.getUserData(OUR_NO_SIZE_LIMIT_KEY)); - } - - public static void doNotCheckFileSizeLimit(@NotNull VirtualFile vFile) { - vFile.putUserData(OUR_NO_SIZE_LIMIT_KEY, Boolean.TRUE); - } - - public static boolean isTooLarge(@NotNull VirtualFile vFile, final long contentSize) { - if (!checkFileSizeLimit(vFile)) return false; - return contentSize > PersistentFSConstants.MAX_INTELLISENSE_FILESIZE; - } - - private static boolean fileSizeIsGreaterThan(@NotNull VirtualFile vFile, final long maxBytes) { - if (vFile instanceof LightVirtualFile) { - // This is optimization in order to avoid conversion of [large] file contents to bytes - final int lengthInChars = ((LightVirtualFile) vFile).getContent().length(); - if (lengthInChars < maxBytes / 2) return false; - if (lengthInChars > maxBytes) return true; - } - - return vFile.getLength() > maxBytes; - } - - @Nullable - protected PsiFile createFile(Language lang) { - if (lang != getBaseLanguage()) return null; - final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(lang); - if (parserDefinition != null) { - return parserDefinition.createFile(this); - } - return null; - } - - @Override - @NotNull - public PsiManager getManager() { - return myManager; - } - - @Override - @NotNull - public CharSequence getContents() { - return getContent().getText(); - } - - @Override - @NotNull - public VirtualFile getVirtualFile() { - return myVirtualFile; - } - - @Nullable - private Document getCachedDocument() { - final Document document = myDocument != null ? myDocument.get() : null; - if (document != null) return document; - return FileDocumentManager.getInstance().getCachedDocument(getVirtualFile()); - } - - @Override - public Document getDocument() { - Document document = myDocument != null ? myDocument.get() : null; - if (document == null/* TODO[ik] make this change && isEventSystemEnabled()*/) { - document = FileDocumentManager.getInstance().getDocument(getVirtualFile()); - myDocument = new SoftReference(document); - } - if (document != null && getContent() instanceof VirtualFileContent) { - setContent(new DocumentContent()); - } - return document; - } - - @Override - public FileViewProvider clone() { - final VirtualFile origFile = getVirtualFile(); - LightVirtualFile copy = new LightVirtualFile(origFile.getName(), origFile.getFileType(), getContents(), origFile.getCharset(), getModificationStamp()); - copy.setOriginalFile(origFile); - copy.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE); - copy.setCharset(origFile.getCharset()); - return createCopy(copy); - } - - @NotNull - @Override - public SingleRootFileViewProvider createCopy(final VirtualFile copy) { - return new SingleRootFileViewProvider(getManager(), copy, false, myBaseLanguage); - } - - @Override - public PsiReference findReferenceAt(final int offset) { - final PsiFileImpl psiFile = (PsiFileImpl) getPsi(getBaseLanguage()); - return findReferenceAt(psiFile, offset); - } - - @Override - public PsiElement findElementAt(final int offset, final Language language) { - final PsiFile psiFile = getPsi(language); - return psiFile != null ? findElementAt(psiFile, offset) : null; - } - - @Override - @Nullable - public PsiReference findReferenceAt(final int offset, @NotNull final Language language) { - final PsiFile psiFile = getPsi(language); - return psiFile != null ? findReferenceAt(psiFile, offset) : null; - } - - @Nullable - private static PsiReference findReferenceAt(final PsiFile psiFile, final int offset) { - if (psiFile == null) return null; - int offsetInElement = offset; - PsiElement child = psiFile.getFirstChild(); - while (child != null) { - final int length = child.getTextLength(); - if (length <= offsetInElement) { - offsetInElement -= length; - child = child.getNextSibling(); - continue; - } - return child.findReferenceAt(offsetInElement); - } - return null; - } - - @Override - public PsiElement findElementAt(final int offset) { - return findElementAt(getPsi(getBaseLanguage()), offset); - } - - - @Override - public PsiElement findElementAt(int offset, Class lang) { - if (!ReflectionCache.isAssignable(lang, getBaseLanguage().getClass())) return null; - return findElementAt(offset); - } - - @Nullable - protected static PsiElement findElementAt(final PsiElement psiFile, final int offset) { - if (psiFile == null) return null; - int offsetInElement = offset; - PsiElement child = psiFile.getFirstChild(); - while (child != null) { - final int length = child.getTextLength(); - if (length <= offsetInElement) { - offsetInElement -= length; - child = child.getNextSibling(); - continue; - } - return child.findElementAt(offsetInElement); - } - return null; - } - - public void forceCachedPsi(final PsiFile psiFile) { - myPsiFile.set(psiFile); - ((PsiManagerEx) myManager).getFileManager().setViewProvider(getVirtualFile(), this); - } - - private Content getContent() { - return myContent; - } - - private void setContent(final Content content) { - myContent = content; - } - - private interface Content { - CharSequence getText(); - - long getModificationStamp(); - } - - private class VirtualFileContent implements Content { - @Override - public CharSequence getText() { - final VirtualFile virtualFile = getVirtualFile(); - if (virtualFile instanceof LightVirtualFile) { - Document doc = getCachedDocument(); - if (doc != null) return doc.getCharsSequence(); - return ((LightVirtualFile) virtualFile).getContent(); - } - - final Document document = getDocument(); - if (document == null) { - return LoadTextUtil.loadText(virtualFile); - } else { - return document.getCharsSequence(); - } - } - - @Override - public long getModificationStamp() { - return getVirtualFile().getModificationStamp(); - } - } - - private class DocumentContent implements Content { - @Override - public CharSequence getText() { - final Document document = getDocument(); - assert document != null; - return document.getCharsSequence(); - } - - @Override - public long getModificationStamp() { - Document document = myDocument == null ? null : myDocument.get(); - if (document != null) return document.getModificationStamp(); - return myVirtualFile.getModificationStamp(); - } - } - - private class PsiFileContent implements Content { - private final PsiFileImpl myFile; - private CharSequence myContent = null; - private final long myModificationStamp; - - private PsiFileContent(final PsiFileImpl file, final long modificationStamp) { - myFile = file; - myModificationStamp = modificationStamp; - } - - @Override - public CharSequence getText() { - if (!myFile.isContentsLoaded()) { - unsetPsiContent(); - return getContents(); - } - if (myContent != null) return myContent; - return myContent = ApplicationManager.getApplication().runReadAction(new Computable() { - public CharSequence compute() { - return myFile.calcTreeElement().getText(); - } - }); - } - - @Override - public long getModificationStamp() { - if (!myFile.isContentsLoaded()) { - unsetPsiContent(); - return SingleRootFileViewProvider.this.getModificationStamp(); - } - return myModificationStamp; - } - } -} diff --git a/idea_fix/src/com/intellij/psi/text/BlockSupport.java b/idea_fix/src/com/intellij/psi/text/BlockSupport.java deleted file mode 100644 index 45a0be4fc74..00000000000 --- a/idea_fix/src/com/intellij/psi/text/BlockSupport.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2000-2009 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.text; - -import com.intellij.lang.ASTNode; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.UserDataHolder; -import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.source.text.DiffLog; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -public abstract class BlockSupport { - public static BlockSupport getInstance(Project project) { - return ServiceManager.getService(project, BlockSupport.class); - } - - public abstract void reparseRange(PsiFile file, int startOffset, int endOffset, @NonNls CharSequence newText) throws IncorrectOperationException; - - @NotNull - public abstract DiffLog reparseRange(@NotNull PsiFile file, - int startOffset, - int endOffset, - int lengthShift, - @NotNull CharSequence newText, - @NotNull ProgressIndicator progressIndicator) throws IncorrectOperationException; - - public static final Key DO_NOT_REPARSE_INCREMENTALLY = Key.create("DO_NOT_REPARSE_INCREMENTALLY"); - public static final Key TREE_TO_BE_REPARSED = Key.create("TREE_TO_BE_REPARSED"); - - public static class ReparsedSuccessfullyException extends RuntimeException { - private final DiffLog myDiffLog; - - public ReparsedSuccessfullyException(@NotNull DiffLog diffLog) { - myDiffLog = diffLog; - } - - @NotNull - public DiffLog getDiffLog() { - return myDiffLog; - } - - @Override - public synchronized Throwable fillInStackTrace() { - return this; - } - } - - // maximal tree depth for which incremental reparse is allowed - // if tree is deeper then it will be replaced completely - to avoid SOEs -// public static final int INCREMENTAL_REPARSE_DEPTH_LIMIT = Registry.intValue("psi.incremental.reparse.depth.limit", 1000); - public static final int INCREMENTAL_REPARSE_DEPTH_LIMIT = 1000; - - public static final Key TREE_DEPTH_LIMIT_EXCEEDED = Key.create("TREE_IS_TOO_DEEP"); - - public static boolean isTooDeep(final UserDataHolder element) { - return element != null && Boolean.TRUE.equals(element.getUserData(TREE_DEPTH_LIMIT_EXCEEDED)); - } -} diff --git a/idea_fix/src/com/intellij/util/ReflectionUtil.java b/idea_fix/src/com/intellij/util/ReflectionUtil.java deleted file mode 100644 index cc9c72caafb..00000000000 --- a/idea_fix/src/com/intellij/util/ReflectionUtil.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright 2000-2009 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.util; - -import com.intellij.openapi.diagnostic.Logger; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.*; -import java.util.ArrayList; -import java.util.Arrays; - -public class ReflectionUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.ReflectionUtil"); - - private ReflectionUtil() { - } - - @Nullable - public static Type resolveVariable(TypeVariable variable, final Class classType) { - return resolveVariable(variable, classType, true); - } - - @Nullable - public static Type resolveVariable(TypeVariable variable, final Class classType, boolean resolveInInterfacesOnly) { - final Class aClass = getRawType(classType); - int index = ArrayUtil.find(ReflectionCache.getTypeParameters(aClass), variable); - if (index >= 0) { - return variable; - } - - final Class[] classes = ReflectionCache.getInterfaces(aClass); - final Type[] genericInterfaces = ReflectionCache.getGenericInterfaces(aClass); - for (int i = 0; i <= classes.length; i++) { - Class anInterface; - if (i < classes.length) { - anInterface = classes[i]; - } else { - anInterface = ReflectionCache.getSuperClass(aClass); - if (resolveInInterfacesOnly || anInterface == null) { - continue; - } - } - final Type resolved = resolveVariable(variable, anInterface); - if (resolved instanceof Class || resolved instanceof ParameterizedType) { - return resolved; - } - if (resolved instanceof TypeVariable) { - final TypeVariable typeVariable = (TypeVariable) resolved; - index = ArrayUtil.find(ReflectionCache.getTypeParameters(anInterface), typeVariable); - if (index < 0) { - LOG.error("Cannot resolve type variable:\n" + "typeVariable = " + typeVariable + "\n" + "genericDeclaration = " + - declarationToString(typeVariable.getGenericDeclaration()) + "\n" + "searching in " + declarationToString(anInterface)); - } - final Type type = i < genericInterfaces.length ? genericInterfaces[i] : aClass.getGenericSuperclass(); - if (type instanceof Class) { - return Object.class; - } - if (type instanceof ParameterizedType) { - return getActualTypeArguments(((ParameterizedType) type))[index]; - } - throw new AssertionError("Invalid type: " + type); - } - } - return null; - } - - public static String declarationToString(final GenericDeclaration anInterface) { - return anInterface.toString() - + Arrays.asList(anInterface.getTypeParameters()) - + " loaded by " + ((Class) anInterface).getClassLoader(); - } - - public static Class getRawType(Type type) { - if (type instanceof Class) { - return (Class) type; - } - if (type instanceof ParameterizedType) { - return getRawType(((ParameterizedType) type).getRawType()); - } - if (type instanceof GenericArrayType) { - //todo[peter] don't create new instance each time - return Array.newInstance(getRawType(((GenericArrayType) type).getGenericComponentType()), 0).getClass(); - } - assert false : type; - return null; - } - - public static Type[] getActualTypeArguments(final ParameterizedType parameterizedType) { - return ReflectionCache.getActualTypeArguments(parameterizedType); - } - - @Nullable - public static Class substituteGenericType(final Type genericType, final Type classType) { - if (genericType instanceof TypeVariable) { - final Class aClass = getRawType(classType); - final Type type = resolveVariable((TypeVariable) genericType, aClass); - if (type instanceof Class) { - return (Class) type; - } - if (type instanceof ParameterizedType) { - return (Class) ((ParameterizedType) type).getRawType(); - } - if (type instanceof TypeVariable && classType instanceof ParameterizedType) { - final int index = ArrayUtil.find(ReflectionCache.getTypeParameters(aClass), type); - if (index >= 0) { - return getRawType(getActualTypeArguments(((ParameterizedType) classType))[index]); - } - } - } else { - return getRawType(genericType); - } - return null; - } - - public static ArrayList collectFields(Class clazz) { - ArrayList result = new ArrayList(); - collectFields(clazz, result); - return result; - } - - public static Field findField(Class clazz, @Nullable Class type, String name) throws NoSuchFieldException { - final ArrayList fields = collectFields(clazz); - for (Field each : fields) { - if (name.equals(each.getName()) && (type == null || each.getType().equals(type))) return each; - } - - throw new NoSuchFieldException("Class: " + clazz + " name: " + name + " type: " + type); - } - - public static Field findAssignableField(Class clazz, Class type, String name) throws NoSuchFieldException { - final ArrayList fields = collectFields(clazz); - for (Field each : fields) { - if (name.equals(each.getName()) && type.isAssignableFrom(each.getType())) return each; - } - - throw new NoSuchFieldException("Class: " + clazz + " name: " + name + " type: " + type); - } - - private static void collectFields(final Class clazz, final ArrayList result) { - final Field[] fields = clazz.getDeclaredFields(); - result.addAll(Arrays.asList(fields)); - final Class superClass = clazz.getSuperclass(); - if (superClass != null) { - collectFields(superClass, result); - } - final Class[] interfaces = clazz.getInterfaces(); - for (Class each : interfaces) { - collectFields(each, result); - } - } - - public static void resetField(Class clazz, Class type, String name) { - try { - resetField(null, findField(clazz, type, name)); - } catch (NoSuchFieldException e) { - LOG.info(e); - } - } - - public static void resetField(Object object, Class type, String name) { - try { - resetField(object, findField(object.getClass(), type, name)); - } catch (NoSuchFieldException e) { - LOG.info(e); - } - } - - public static void resetField(Object object, String name) { - try { - resetField(object, findField(object.getClass(), null, name)); - } catch (NoSuchFieldException e) { - LOG.info(e); - } - } - - public static void resetField(@Nullable final Object object, final Field field) { -// field.setAccessible(true); - Class type = field.getType(); - try { - if (type.isPrimitive()) { - if (boolean.class.equals(type)) { - field.set(object, Boolean.FALSE); - } else if (int.class.equals(type)) { - field.set(object, new Integer(0)); - } else if (double.class.equals(type)) { - field.set(object, new Double(0)); - } else if (float.class.equals(type)) { - field.set(object, new Float(0)); - } - } else { - field.set(object, null); - } - } catch (IllegalAccessException e) { - LOG.info(e); - } - } - - @Nullable - public static Method findMethod(Method[] methods, @NonNls @NotNull String name, Class... parameters) { - for (final Method method : methods) { - if (name.equals(method.getName()) && Arrays.equals(parameters, method.getParameterTypes())) return method; - } - return null; - } - - @Nullable - public static Method getMethod(@NotNull Class aClass, @NonNls @NotNull String name, Class... parameters) { - return findMethod(ReflectionCache.getMethods(aClass), name, parameters); - } - - @Nullable - public static Method getDeclaredMethod(@NotNull Class aClass, @NonNls @NotNull String name, Class... parameters) { - return findMethod(aClass.getDeclaredMethods(), name, parameters); - } - - public static Object getField(Class objectClass, Object object, Class type, @NonNls String name) { - try { - final Field field = findAssignableField(objectClass, type, name); -// field.setAccessible(true); - return field.get(object); - } catch (NoSuchFieldException e) { - LOG.debug(e); - return null; - } catch (IllegalAccessException e) { - LOG.debug(e); - return null; - } - } - - public static Type resolveVariableInHierarchy(final TypeVariable variable, final Class aClass) { - Type type; - Class current = aClass; - while ((type = resolveVariable(variable, current, false)) == null) { - current = ReflectionCache.getSuperClass(current); - if (current == null) { - return null; - } - } - if (type instanceof TypeVariable) { - return resolveVariableInHierarchy((TypeVariable) type, aClass); - } - return type; - } - - @NotNull - public static Constructor getDefaultConstructor(final Class aClass) { - try { - final Constructor constructor = aClass.getConstructor(); -// constructor.setAccessible(true); - return constructor; - } catch (NoSuchMethodException e) { - LOG.error("No default constructor in " + aClass, e); - return null; - } - } - - @NotNull - public static T createInstance(final Constructor constructor, final Object... args) { - try { - return constructor.newInstance(args); - } catch (InstantiationException e) { - LOG.error(e); - return null; - } catch (IllegalAccessException e) { - LOG.error(e); - return null; - } catch (InvocationTargetException e) { - LOG.error(e); - return null; - } - } -} diff --git a/jetTests/test/ExampleTestSuite.java b/jetTests/test/ExampleTestSuite.java deleted file mode 100644 index 288d42b3743..00000000000 --- a/jetTests/test/ExampleTestSuite.java +++ /dev/null @@ -1,33 +0,0 @@ -import junit.framework.Test; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.JetLiteFixture; - - -public final class ExampleTestSuite extends JetLiteFixture { - private String name; - - public ExampleTestSuite(@NonNls String dataPath, String name) { - this.name = name; - } - - public String getName() { - return "test" + name; - } - - public void runTest() throws Exception { - - } - - - public static Test suite() { - return JetTestCaseBuilder.suiteForDirectory(JetTestCaseBuilder.getTestDataPathBase(), - "/checkerWithErrorTypes/quick", true, new JetTestCaseBuilder.NamedTestFactory() { - @NotNull - @Override - public Test createTest(@NotNull String dataPath, @NotNull String name) { - return (new ExampleTestSuite(dataPath, name)); - } - }); - } -}