mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+1
-1
@@ -91,7 +91,7 @@ public class IdIndex extends FileBasedIndexExtension<IdIndexEntry, Integer> {
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 11 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set
|
||||
return 12 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -103,7 +103,7 @@ public class TrigramIndex extends ScalarIndexExtension<Integer> implements Custo
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return ENABLED ? 2 + (IdIndex.ourSnapshotMappingsEnabled ? 0xFF:0) : 1;
|
||||
return ENABLED ? 3 + (IdIndex.ourSnapshotMappingsEnabled ? 0xFF:0) : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -135,7 +135,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
LOG.info("Version has changed for stub index " + extension.getKey() + ". The index will be rebuilt.");
|
||||
}
|
||||
FileUtil.delete(indexRootDir);
|
||||
IndexingStamp.rewriteVersion(versionFile, version);
|
||||
IndexingStamp.rewriteVersion(versionFile, version); // todo snapshots indices
|
||||
}
|
||||
|
||||
for (int attempt = 0; attempt < 2; attempt++) {
|
||||
@@ -157,7 +157,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
LOG.info(e);
|
||||
needRebuild = true;
|
||||
FileUtil.delete(indexRootDir);
|
||||
IndexingStamp.rewriteVersion(versionFile, version);
|
||||
IndexingStamp.rewriteVersion(versionFile, version); // todo snapshots indices
|
||||
}
|
||||
}
|
||||
return needRebuild;
|
||||
@@ -445,7 +445,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
}
|
||||
|
||||
private static class MyIndex<K> extends MapReduceIndex<K, StubIdList, Void> {
|
||||
public MyIndex(final IndexStorage<K, StubIdList> storage) {
|
||||
public MyIndex(final IndexStorage<K, StubIdList> storage) throws IOException {
|
||||
super(null, null, storage);
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
@NotNull
|
||||
@Override
|
||||
public UpdatableIndex<Integer, SerializedStubTree, FileContent> createIndexImplementation(@NotNull final ID<Integer, SerializedStubTree> indexId, @NotNull final FileBasedIndex owner, @NotNull IndexStorage<Integer, SerializedStubTree> storage)
|
||||
throws StorageException {
|
||||
throws StorageException, IOException {
|
||||
if (storage instanceof MemoryIndexStorage) {
|
||||
final MemoryIndexStorage<Integer, SerializedStubTree> memStorage = (MemoryIndexStorage<Integer, SerializedStubTree>)storage;
|
||||
memStorage.addBufferingStateListener(new MemoryIndexStorage.BufferingStateListener() {
|
||||
@@ -273,7 +273,8 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
private class MyIndex extends MapReduceIndex<Integer, SerializedStubTree, FileContent> {
|
||||
private StubIndexImpl myStubIndex;
|
||||
|
||||
public MyIndex(final ID<Integer, SerializedStubTree> indexId, final IndexStorage<Integer, SerializedStubTree> storage, final DataIndexer<Integer, SerializedStubTree, FileContent> indexer) throws StorageException {
|
||||
public MyIndex(final ID<Integer, SerializedStubTree> indexId, final IndexStorage<Integer, SerializedStubTree> storage, final DataIndexer<Integer, SerializedStubTree, FileContent> indexer)
|
||||
throws StorageException, IOException {
|
||||
super(indexId, indexer, storage);
|
||||
checkNameStorage();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.indexing;
|
||||
|
||||
import com.intellij.openapi.util.io.ByteSequence;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Created by Maxim.Mossienko on 5/7/2014.
|
||||
*/
|
||||
class ByteSequenceDataExternalizer implements DataExternalizer<ByteSequence> {
|
||||
static final ByteSequenceDataExternalizer INSTANCE = new ByteSequenceDataExternalizer();
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, ByteSequence value) throws IOException {
|
||||
out.write(value.getBytes(), value.getOffset(), value.getLength()); // todo fix double copying
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteSequence read(@NotNull DataInput in) throws IOException {
|
||||
byte[] buf = new byte[((InputStream)in).available()]; // todo fix double copying
|
||||
in.readFully(buf);
|
||||
return new ByteSequence(buf);
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package com.intellij.util.indexing;
|
||||
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.ContentHashesUtil;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon;
|
||||
import com.intellij.util.io.IOUtil;
|
||||
@@ -33,28 +31,27 @@ import java.security.MessageDigest;
|
||||
* @since 4/10/2014.
|
||||
*/
|
||||
class ContentHashesSupport {
|
||||
private static final ContentHashesUtil.HashEnumerator ourHashesWithFileType;
|
||||
private static volatile ContentHashesUtil.HashEnumerator ourHashesWithFileType;
|
||||
|
||||
static {
|
||||
ContentHashesUtil.HashEnumerator hashEnumerator = null;
|
||||
try {
|
||||
final File hashEnumeratorFile = new File(PathManager.getIndexRoot(), "hashesWithFileType");
|
||||
hashEnumerator = IOUtil.openCleanOrResetBroken(new ThrowableComputable<ContentHashesUtil.HashEnumerator, IOException>() {
|
||||
@Override
|
||||
public ContentHashesUtil.HashEnumerator compute() throws IOException {
|
||||
return new ContentHashesUtil.HashEnumerator(hashEnumeratorFile, null);
|
||||
}
|
||||
}, hashEnumeratorFile);
|
||||
FlushingDaemon.everyFiveSeconds(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (ourHashesWithFileType.isDirty()) ourHashesWithFileType.force();
|
||||
}
|
||||
});
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
} finally {
|
||||
ourHashesWithFileType = hashEnumerator;
|
||||
static void initContentHashesEnumerator() throws IOException {
|
||||
if (ourHashesWithFileType != null) return;
|
||||
synchronized (ContentHashesSupport.class) {
|
||||
if (ourHashesWithFileType != null) return;
|
||||
ContentHashesUtil.HashEnumerator hashEnumerator = null;
|
||||
final File hashEnumeratorFile = new File(IndexInfrastructure.getPersistentIndexRoot(), "hashesWithFileType");
|
||||
try {
|
||||
hashEnumerator = new ContentHashesUtil.HashEnumerator(hashEnumeratorFile, null);
|
||||
FlushingDaemon.everyFiveSeconds(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (ourHashesWithFileType.isDirty()) ourHashesWithFileType.force();
|
||||
}
|
||||
});
|
||||
ourHashesWithFileType = hashEnumerator;
|
||||
} catch (IOException ex) {
|
||||
IOUtil.deleteAllFilesStartingWith(hashEnumeratorFile);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -21,8 +21,10 @@ package com.intellij.util.indexing;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class CustomImplementationFileBasedIndexExtension<K, V, I> extends FileBasedIndexExtension<K, V> {
|
||||
@NotNull
|
||||
public abstract UpdatableIndex<K, V, I> createIndexImplementation(@NotNull ID<K, V> indexId, @NotNull FileBasedIndex owner, @NotNull IndexStorage<K, V> storage)
|
||||
throws StorageException;
|
||||
throws StorageException, IOException;
|
||||
}
|
||||
@@ -381,7 +381,10 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
versionChanged = true;
|
||||
LOG.info("Version has changed for index " + name + ". The index will be rebuilt.");
|
||||
}
|
||||
FileUtil.delete(IndexInfrastructure.getIndexRootDir(name));
|
||||
if (extension.hasSnapshotMapping() && (isCurrentVersionCorrupted || versionChanged)) {
|
||||
safeDelete(IndexInfrastructure.getPersistentIndexRootDir(name));
|
||||
}
|
||||
safeDelete(IndexInfrastructure.getIndexRootDir(name));
|
||||
IndexingStamp.rewriteVersion(versionFile, version);
|
||||
}
|
||||
|
||||
@@ -394,8 +397,14 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
throws IOException {
|
||||
MapIndexStorage<K, V> storage = null;
|
||||
final ID<K, V> name = extension.getName();
|
||||
boolean contentHashesEnumeratorOk = false;
|
||||
|
||||
for (int attempt = 0; attempt < 2; attempt++) {
|
||||
try {
|
||||
if (extension.hasSnapshotMapping()) {
|
||||
ContentHashesSupport.initContentHashesEnumerator();
|
||||
contentHashesEnumeratorOk = true;
|
||||
}
|
||||
storage = new MapIndexStorage<K, V>(
|
||||
IndexInfrastructure.getStorageFile(name),
|
||||
extension.getKeyDescriptor(),
|
||||
@@ -443,6 +452,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info(e);
|
||||
boolean instantiatedStorage = storage != null;
|
||||
try {
|
||||
if (storage != null) storage.close();
|
||||
storage = null;
|
||||
@@ -450,12 +460,22 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
|
||||
FileUtil.delete(IndexInfrastructure.getIndexRootDir(name));
|
||||
safeDelete(IndexInfrastructure.getIndexRootDir(name));
|
||||
|
||||
if (extension.hasSnapshotMapping() && (!contentHashesEnumeratorOk || instantiatedStorage)) {
|
||||
safeDelete(IndexInfrastructure.getPersistentIndexRootDir(name)); // todo there is possibility of corruption of storage and content hashes
|
||||
}
|
||||
IndexingStamp.rewriteVersion(versionFile, version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean safeDelete(File dir) {
|
||||
File directory = FileUtil.findSequentNonexistentFile(dir.getParentFile(), dir.getName(), "");
|
||||
boolean success = dir.renameTo(directory);
|
||||
return FileUtil.delete(success ? directory:dir);
|
||||
}
|
||||
|
||||
private static void saveRegisteredIndices(@NotNull Collection<ID<?, ?>> ids) {
|
||||
final File file = getRegisteredIndicesFile();
|
||||
try {
|
||||
@@ -519,7 +539,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
extension.hasSnapshotMapping() && IdIndex.ourSnapshotMappingsEnabled
|
||||
? createInputsIndexExternalizer(extension, indexId, extension.getKeyDescriptor())
|
||||
: null;
|
||||
index = new MapReduceIndex<K, V, FileContent>(indexId, extension.getIndexer(), storage, externalizer);
|
||||
index = new MapReduceIndex<K, V, FileContent>(indexId, extension.getIndexer(), storage, externalizer, extension.getValueExternalizer());
|
||||
}
|
||||
index.setInputIdToDataKeysIndex(new Factory<PersistentHashMap<Integer, Collection<K>>>() {
|
||||
@Override
|
||||
@@ -1620,7 +1640,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
indicesToDrop.remove(key.toString());
|
||||
}
|
||||
for (String s : indicesToDrop) {
|
||||
FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s)));
|
||||
safeDelete(IndexInfrastructure.getIndexRootDir(ID.create(s)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1715,7 +1735,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
byte[] hash;
|
||||
try {
|
||||
currentBytes = content.getBytes();
|
||||
hash = fileType.isBinary() ? null:ContentHashesSupport.calcContentHashWithFileType(currentBytes, fileType);
|
||||
hash = fileType.isBinary() || !IdIndex.ourSnapshotMappingsEnabled ? null:ContentHashesSupport.calcContentHashWithFileType(currentBytes, fileType);
|
||||
}
|
||||
catch (IOException e) {
|
||||
currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY;
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.util.Locale;
|
||||
public class IndexInfrastructure {
|
||||
private static final boolean ourUnitTestMode = ApplicationManager.getApplication().isUnitTestMode();
|
||||
private static final String STUB_VERSIONS = ".versions";
|
||||
private static final String PERSISTENT_INDEX_DIRECTORY_NAME = ".persistent";
|
||||
|
||||
private IndexInfrastructure() {
|
||||
}
|
||||
@@ -60,14 +61,35 @@ public class IndexInfrastructure {
|
||||
return getIndexDirectory(indexName, false);
|
||||
}
|
||||
|
||||
public static File getPersistentIndexRoot() {
|
||||
File indexDir = new File(PathManager.getIndexRoot() + File.separator + PERSISTENT_INDEX_DIRECTORY_NAME);
|
||||
indexDir.mkdirs();
|
||||
return indexDir;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File getPersistentIndexRootDir(@NotNull ID<?, ?> indexName) {
|
||||
return getIndexDirectory(indexName, false, PERSISTENT_INDEX_DIRECTORY_NAME);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File getIndexDirectory(@NotNull ID<?, ?> indexName, boolean forVersion) {
|
||||
return getIndexDirectory(indexName, forVersion, "");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File getIndexDirectory(@NotNull ID<?, ?> indexName, boolean forVersion, String relativePath) {
|
||||
final String dirName = indexName.toString().toLowerCase(Locale.US);
|
||||
// store StubIndices under StubUpdating index' root to ensure they are deleted
|
||||
// when StubUpdatingIndex version is changed
|
||||
final File indexDir = indexName instanceof StubIndexKey
|
||||
? new File(getIndexRootDir(StubUpdatingIndex.INDEX_ID), forVersion ? STUB_VERSIONS : dirName)
|
||||
: new File(PathManager.getIndexRoot(), dirName);
|
||||
File indexDir;
|
||||
|
||||
if (indexName instanceof StubIndexKey) {
|
||||
// store StubIndices under StubUpdating index' root to ensure they are deleted
|
||||
// when StubUpdatingIndex version is changed
|
||||
indexDir = new File(getIndexDirectory(StubUpdatingIndex.INDEX_ID, false, relativePath), forVersion ? STUB_VERSIONS : dirName);
|
||||
} else {
|
||||
if (relativePath.length() > 0) relativePath = File.separator + relativePath;
|
||||
indexDir = new File(PathManager.getIndexRoot() + relativePath, dirName);
|
||||
}
|
||||
indexDir.mkdirs();
|
||||
return indexDir;
|
||||
}
|
||||
|
||||
@@ -19,21 +19,22 @@ package com.intellij.util.indexing;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
|
||||
import com.intellij.openapi.util.io.ByteSequence;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.io.*;
|
||||
import com.intellij.util.io.DataOutputStream;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.TObjectObjectProcedure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@@ -48,10 +49,12 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
private final DataIndexer<Key, Value, Input> myIndexer;
|
||||
@NotNull protected final IndexStorage<Key, Value> myStorage;
|
||||
private final boolean myHasSnapshotMapping;
|
||||
|
||||
private final DataExternalizer<Value> myValueExternalizer;
|
||||
private final DataExternalizer<Collection<Key>> mySnapshotIndexExternalizer;
|
||||
|
||||
private PersistentHashMap<Integer, Collection<Key>> myInputsIndex;
|
||||
private PersistentHashMap<Integer, Collection<Key>> mySnapshotMapping;
|
||||
private final PersistentHashMap<Integer, ByteSequence> myContents;
|
||||
private PersistentHashMap<Integer, Integer> myInputsSnapshotMapping;
|
||||
|
||||
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
|
||||
@@ -60,19 +63,34 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
|
||||
public MapReduceIndex(@Nullable final ID<Key, Value> indexId,
|
||||
DataIndexer<Key, Value, Input> indexer,
|
||||
@NotNull IndexStorage<Key, Value> storage) {
|
||||
this(indexId, indexer, storage, null);
|
||||
@NotNull IndexStorage<Key, Value> storage) throws IOException {
|
||||
this(indexId, indexer, storage, null, null);
|
||||
}
|
||||
|
||||
public MapReduceIndex(@Nullable final ID<Key, Value> indexId,
|
||||
DataIndexer<Key, Value, Input> indexer,
|
||||
@NotNull IndexStorage<Key, Value> storage,
|
||||
DataExternalizer<Collection<Key>> snapshotIndexExternalizer) {
|
||||
DataExternalizer<Collection<Key>> snapshotIndexExternalizer,
|
||||
DataExternalizer<Value> valueDataExternalizer) throws IOException {
|
||||
myIndexId = indexId;
|
||||
myIndexer = indexer;
|
||||
myStorage = storage;
|
||||
myHasSnapshotMapping = snapshotIndexExternalizer != null;
|
||||
|
||||
mySnapshotIndexExternalizer = snapshotIndexExternalizer;
|
||||
myValueExternalizer = valueDataExternalizer;
|
||||
final File saved = myHasSnapshotMapping && myIndexId != null ? new File(IndexInfrastructure.getPersistentIndexRootDir(myIndexId), "values") : null;
|
||||
|
||||
if (saved != null) {
|
||||
try {
|
||||
myContents = new PersistentHashMap<Integer, ByteSequence>(saved, EnumeratorIntegerDescriptor.INSTANCE, ByteSequenceDataExternalizer.INSTANCE);
|
||||
} catch (IOException ex) {
|
||||
IOUtil.deleteAllFilesStartingWith(saved);
|
||||
throw ex;
|
||||
}
|
||||
} else {
|
||||
myContents = null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -93,10 +111,6 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
cleanMapping(myInputsSnapshotMapping);
|
||||
myInputsSnapshotMapping = createInputSnapshotMapping();
|
||||
}
|
||||
if (mySnapshotMapping != null) {
|
||||
cleanMapping(mySnapshotMapping);
|
||||
mySnapshotMapping = createSnapshotMappingIndex();
|
||||
}
|
||||
}
|
||||
catch (StorageException e) {
|
||||
LOG.error(e);
|
||||
@@ -112,17 +126,19 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
private PersistentHashMap<Integer, Integer> createInputSnapshotMapping() throws IOException {
|
||||
assert myIndexId != null;
|
||||
final File fileIdToHashIdFile = new File(IndexInfrastructure.getIndexRootDir(myIndexId), "fileIdToHashId");
|
||||
return IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentHashMap<Integer, Integer>, IOException>() {
|
||||
@Override
|
||||
public PersistentHashMap<Integer, Integer> compute() throws IOException {
|
||||
return new PersistentHashMap<Integer, Integer>(fileIdToHashIdFile, EnumeratorIntegerDescriptor.INSTANCE, EnumeratorIntegerDescriptor.INSTANCE, 4096) {
|
||||
@Override
|
||||
protected boolean wantCompactIntegralValues() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}, fileIdToHashIdFile);
|
||||
try {
|
||||
return new PersistentHashMap<Integer, Integer>(fileIdToHashIdFile, EnumeratorIntegerDescriptor.INSTANCE,
|
||||
EnumeratorIntegerDescriptor.INSTANCE, 4096) {
|
||||
@Override
|
||||
protected boolean wantCompactIntegralValues() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (IOException ex) {
|
||||
IOUtil.deleteAllFilesStartingWith(fileIdToHashIdFile);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private static void cleanMapping(@NotNull PersistentHashMap<?, ?> index) {
|
||||
@@ -142,7 +158,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
getReadLock().lock();
|
||||
doForce(myInputsIndex);
|
||||
doForce(myInputsSnapshotMapping);
|
||||
doForce(mySnapshotMapping);
|
||||
doForce(myContents);
|
||||
myStorage.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -179,7 +195,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
finally {
|
||||
doClose(myInputsIndex);
|
||||
doClose(myInputsSnapshotMapping);
|
||||
doClose(mySnapshotMapping);
|
||||
doClose(myContents);
|
||||
}
|
||||
}
|
||||
catch (StorageException e) {
|
||||
@@ -242,22 +258,10 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
myInputsIndexFactory = factory;
|
||||
if (myHasSnapshotMapping) {
|
||||
myInputsSnapshotMapping = createInputSnapshotMapping();
|
||||
mySnapshotMapping = createSnapshotMappingIndex();
|
||||
}
|
||||
myInputsIndex = createInputsIndex();
|
||||
}
|
||||
|
||||
private PersistentHashMap<Integer, Collection<Key>> createSnapshotMappingIndex() throws IOException {
|
||||
assert myIndexId != null;
|
||||
final File hashIdToKeysFile = new File(IndexInfrastructure.getIndexRootDir(myIndexId), "hashIdToKeys");
|
||||
return IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentHashMap<Integer, Collection<Key>>, IOException>() {
|
||||
@Override
|
||||
public PersistentHashMap<Integer, Collection<Key>> compute() throws IOException {
|
||||
return new PersistentHashMap<Integer, Collection<Key>>(hashIdToKeysFile, EnumeratorIntegerDescriptor.INSTANCE, mySnapshotIndexExternalizer);
|
||||
}
|
||||
}, hashIdToKeysFile);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PersistentHashMap<Integer, Collection<Key>> createInputsIndex() throws IOException {
|
||||
Factory<PersistentHashMap<Integer, Collection<Key>>> factory = myInputsIndexFactory;
|
||||
@@ -275,40 +279,64 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final boolean doReadSavedPersistentData = SystemProperties.getBooleanProperty("idea.read.saved.persistent.index", false);
|
||||
@NotNull
|
||||
@Override
|
||||
public final Computable<Boolean> update(final int inputId, @Nullable Input content) {
|
||||
final boolean weProcessPhysicalContent = content == null ||
|
||||
(content instanceof FileContent &&
|
||||
((FileContent)content).getUserData(FileBasedIndexImpl.ourPhysicalContentKey) != null);
|
||||
|
||||
final Map<Key, Value> data = content != null ? myIndexer.map(content) : Collections.<Key, Value>emptyMap();
|
||||
Map<Key, Value> data = null;
|
||||
boolean havePersistentData = false;
|
||||
Integer hashId = null;
|
||||
|
||||
if (myContents != null && weProcessPhysicalContent && content != null) {
|
||||
try {
|
||||
hashId = getHashOfContent((FileContent)content);
|
||||
if (doReadSavedPersistentData) {
|
||||
ByteSequence bytes = myContents.get(hashId);
|
||||
if (bytes != null) {
|
||||
data = deserializeSavedPersistentData(bytes);
|
||||
havePersistentData = true;
|
||||
}
|
||||
} else {
|
||||
havePersistentData = myContents.containsMapping(hashId);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
// todo:
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (data == null) data = content != null ? myIndexer.map(content) : Collections.<Key, Value>emptyMap();
|
||||
|
||||
if (hashId != null && !havePersistentData && data.size() > 0) {
|
||||
savePersistentData(data, hashId);
|
||||
}
|
||||
ProgressManager.checkCanceled();
|
||||
|
||||
final NotNullComputable<Collection<Key>> oldKeysGetter;
|
||||
final int savedInputId;
|
||||
|
||||
boolean weProcessPhysicalContent = content == null ||
|
||||
(content instanceof FileContent &&
|
||||
((FileContent)content).getUserData(FileBasedIndexImpl.ourPhysicalContentKey) != null);
|
||||
|
||||
if (myHasSnapshotMapping && weProcessPhysicalContent) {
|
||||
try { // optimistically (out of index update write section) read current snapshot keys for file
|
||||
final Integer hashId = myInputsSnapshotMapping.get(inputId);
|
||||
final Collection<Key> keys = hashId != null ? mySnapshotMapping.get(hashId): null;
|
||||
try {
|
||||
|
||||
oldKeysGetter = new NotNullComputable<Collection<Key>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Key> compute() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Key> compute() {
|
||||
try {
|
||||
Integer currentHashId = myInputsSnapshotMapping.get(inputId);
|
||||
Collection<Key> currentKeys;
|
||||
if ((currentHashId == null && hashId == null) || (currentHashId != null && currentHashId.equals(hashId))) {
|
||||
currentKeys = keys;
|
||||
} else { // optimistic reading file's current keys failed
|
||||
currentKeys = currentHashId != null ? mySnapshotMapping.get(currentHashId): null;
|
||||
if (currentHashId != null) {
|
||||
ByteSequence byteSequence = myContents.get(currentHashId);
|
||||
currentKeys = byteSequence != null ? deserializeSavedPersistentData(byteSequence).keySet() : Collections.<Key>emptyList();
|
||||
}
|
||||
else {
|
||||
currentKeys = Collections.emptyList();
|
||||
}
|
||||
|
||||
return currentKeys == null ? Collections.<Key>emptyList() : currentKeys;
|
||||
return currentKeys;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -316,22 +344,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
};
|
||||
|
||||
if (content instanceof FileContent) {
|
||||
FileContent fileContent = (FileContent)content;
|
||||
Integer previouslyCalculatedContentHashId = fileContent.getUserData(ourSavedContentHashIdKey);
|
||||
if (previouslyCalculatedContentHashId == null) {
|
||||
byte[] hash = fileContent instanceof FileContentImpl ? ((FileContentImpl)fileContent).getHash():null;
|
||||
if (hash == null) {
|
||||
previouslyCalculatedContentHashId = ContentHashesSupport.calcContentHashIdWithFileType(fileContent.getContent(), fileContent.getFileType());
|
||||
} else {
|
||||
previouslyCalculatedContentHashId = ContentHashesSupport.enumerateHash(hash);
|
||||
}
|
||||
fileContent.putUserData(ourSavedContentHashIdKey, previouslyCalculatedContentHashId);
|
||||
}
|
||||
|
||||
savedInputId = previouslyCalculatedContentHashId;
|
||||
if (!mySnapshotMapping.containsMapping(savedInputId)) { // save current snapshot keys out of index update write section
|
||||
mySnapshotMapping.put(savedInputId, data.keySet());
|
||||
}
|
||||
savedInputId = getHashOfContent((FileContent)content);
|
||||
} else {
|
||||
savedInputId = NULL_MAPPING;
|
||||
}
|
||||
@@ -356,6 +369,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
}
|
||||
|
||||
// do not depend on content!
|
||||
final Map<Key, Value> finalData = data;
|
||||
return new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
@@ -364,7 +378,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
updateWithMap(inputId, savedInputId, data, oldKeysGetter);
|
||||
updateWithMap(inputId, savedInputId, finalData, oldKeysGetter);
|
||||
}
|
||||
catch (StorageException ex) {
|
||||
exRef.set(ex);
|
||||
@@ -383,6 +397,74 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
};
|
||||
}
|
||||
|
||||
private Map<Key, Value> deserializeSavedPersistentData(ByteSequence bytes) throws IOException {
|
||||
DataInputStream stream = new DataInputStream(new UnsyncByteArrayInputStream(bytes.getBytes(), bytes.getOffset(), bytes.getLength()));
|
||||
int pairs = DataInputOutputUtil.readINT(stream);
|
||||
if (pairs == 0) return Collections.emptyMap();
|
||||
Map<Key, Value> result = new THashMap<Key, Value>(pairs);
|
||||
while (stream.available() > 0) {
|
||||
Value value = myValueExternalizer.read(stream);
|
||||
Collection<Key> keys = mySnapshotIndexExternalizer.read(stream);
|
||||
for(Key k:keys) result.put(k, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Integer getHashOfContent(FileContent content) throws IOException {
|
||||
Integer previouslyCalculatedContentHashId = content.getUserData(ourSavedContentHashIdKey);
|
||||
if (previouslyCalculatedContentHashId == null) {
|
||||
byte[] hash = content instanceof FileContentImpl ? ((FileContentImpl)content).getHash():null;
|
||||
if (hash == null) {
|
||||
previouslyCalculatedContentHashId = ContentHashesSupport
|
||||
.calcContentHashIdWithFileType(content.getContent(), content.getFileType());
|
||||
} else {
|
||||
previouslyCalculatedContentHashId = ContentHashesSupport.enumerateHash(hash);
|
||||
}
|
||||
content.putUserData(ourSavedContentHashIdKey, previouslyCalculatedContentHashId);
|
||||
}
|
||||
return previouslyCalculatedContentHashId;
|
||||
}
|
||||
|
||||
private static final ThreadLocalCachedByteArray ourSpareByteArray = new ThreadLocalCachedByteArray();
|
||||
|
||||
private void savePersistentData(Map<Key, Value> data, int id) {
|
||||
try {
|
||||
BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(ourSpareByteArray.getBuffer(4 * data.size()));
|
||||
DataOutputStream stream = new DataOutputStream(out);
|
||||
int size = data.size();
|
||||
DataInputOutputUtil.writeINT(stream, size);
|
||||
|
||||
if (size > 0) {
|
||||
THashMap<Value, List<Key>> values = new THashMap<Value, List<Key>>();
|
||||
List<Key> keysForNullValue = null;
|
||||
for (Map.Entry<Key, Value> e : data.entrySet()) {
|
||||
Value value = e.getValue();
|
||||
|
||||
List<Key> keys = value != null ? values.get(value):keysForNullValue;
|
||||
if (keys == null) {
|
||||
if (value != null) values.put(value, keys = new SmartList<Key>());
|
||||
else keys = keysForNullValue = new SmartList<Key>();
|
||||
}
|
||||
keys.add(e.getKey());
|
||||
}
|
||||
|
||||
if (keysForNullValue != null) {
|
||||
myValueExternalizer.save(stream, null);
|
||||
mySnapshotIndexExternalizer.save(stream, keysForNullValue);
|
||||
}
|
||||
|
||||
for(Value value:values.keySet()) {
|
||||
myValueExternalizer.save(stream, value);
|
||||
mySnapshotIndexExternalizer.save(stream, values.get(value));
|
||||
}
|
||||
}
|
||||
|
||||
myContents.put(id, new ByteSequence(out.getInternalBuffer(), 0, out.size()));
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static final com.intellij.openapi.util.Key<Integer> ourSavedContentHashIdKey = com.intellij.openapi.util.Key.create("saved.content.hash.id");
|
||||
|
||||
protected void updateWithMap(final int inputId,
|
||||
|
||||
@@ -62,7 +62,7 @@ import java.util.*;
|
||||
},
|
||||
storageChooser = HttpConfigurable.StorageChooser.class
|
||||
)
|
||||
public class HttpConfigurable implements PersistentStateComponent<HttpConfigurable>, ApplicationComponent, JDOMExternalizable,
|
||||
public class HttpConfigurable implements PersistentStateComponent<HttpConfigurable>, ApplicationComponent,
|
||||
ExportableApplicationComponent {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.util.net.HttpConfigurable");
|
||||
public boolean PROXY_TYPE_IS_SOCKS = false;
|
||||
@@ -98,6 +98,7 @@ public class HttpConfigurable implements PersistentStateComponent<HttpConfigurab
|
||||
|
||||
@Override
|
||||
public HttpConfigurable getState() {
|
||||
CommonProxy.isInstalledAssertion();
|
||||
final HttpConfigurable state = new HttpConfigurable();
|
||||
XmlSerializerUtil.copyBean(this, state);
|
||||
if (!KEEP_PROXY_PASSWORD) {
|
||||
@@ -306,15 +307,14 @@ public class HttpConfigurable implements PersistentStateComponent<HttpConfigurab
|
||||
}
|
||||
}
|
||||
|
||||
//these methods are preserved for compatibility
|
||||
@Override
|
||||
//these methods are preserved for compatibility with com.intellij.openapi.project.impl.IdeaServerSettings
|
||||
@Deprecated
|
||||
public void readExternal(Element element) throws InvalidDataException {
|
||||
loadState(XmlSerializer.deserialize(element, HttpConfigurable.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void writeExternal(Element element) throws WriteExternalException {
|
||||
CommonProxy.isInstalledAssertion();
|
||||
XmlSerializer.serializeInto(getState(), element);
|
||||
if (USE_PROXY_PAC && USE_HTTP_PROXY && ! ApplicationManager.getApplication().isDisposed()) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 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.
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.components.StorageId;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizable;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.util.xmlb.Accessor;
|
||||
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
|
||||
@@ -92,7 +93,11 @@ class DefaultStateSerializer {
|
||||
//assert mergeInto == null;
|
||||
return (T)stateElement;
|
||||
}
|
||||
else if (JDOMExternalizable.class.isAssignableFrom(stateClass) && mergeInto == null) {
|
||||
else if (JDOMExternalizable.class.isAssignableFrom(stateClass)) {
|
||||
if (mergeInto != null) {
|
||||
String elementText = JDOMUtil.writeElement(stateElement, "\n");
|
||||
LOG.error("State is " + stateClass.getName() + ", merge into is " + mergeInto.toString() + ", state element text is " + elementText);
|
||||
}
|
||||
try {
|
||||
final T t = stateClass.newInstance();
|
||||
try {
|
||||
|
||||
+14
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2012 Bas Leijdekkers
|
||||
* Copyright 2011-2014 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -227,12 +227,23 @@ public class MismatchedStringBuilderQueryUpdateInspection extends BaseInspection
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
if (updated) {
|
||||
return;
|
||||
}
|
||||
super.visitMethodCallExpression(expression);
|
||||
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
|
||||
checkReferenceExpression(expression.getMethodExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
|
||||
if (updated) {
|
||||
return;
|
||||
}
|
||||
super.visitMethodReferenceExpression(expression);
|
||||
checkReferenceExpression(expression);
|
||||
}
|
||||
|
||||
private void checkReferenceExpression(PsiReferenceExpression methodExpression) {
|
||||
final String name = methodExpression.getReferenceName();
|
||||
if (!updateNames.contains(name)) {
|
||||
return;
|
||||
|
||||
+14
-1
@@ -7,7 +7,7 @@ public class MismatchedStringBuilderQueryUpdate {
|
||||
b.append("");
|
||||
System.out.println("" + b + "");
|
||||
|
||||
final StringBuilder c = new StringBuilder();
|
||||
final StringBuilder <warning descr="Contents of StringBuilder 'c' are updated, but never queried">c</warning> = new StringBuilder();
|
||||
c.append(' ');
|
||||
}
|
||||
|
||||
@@ -17,4 +17,17 @@ public class MismatchedStringBuilderQueryUpdate {
|
||||
sb.append("abc");
|
||||
return sb.reverse();
|
||||
}
|
||||
|
||||
void indexedList(List<String> list) {
|
||||
StringBuilder stringBuilder = new StringBuilder(); // <--- false warning here
|
||||
list.forEach(stringBuilder::append);
|
||||
System.out.println(stringBuilder.toString());
|
||||
}
|
||||
}
|
||||
interface List<T> {
|
||||
default void forEach(Consumer<? super T> action) {
|
||||
}
|
||||
}
|
||||
interface Consumer<T> {
|
||||
void accept(T t);
|
||||
}
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>MismatchedStringBuilderQueryUpdate.java</file>
|
||||
<line>10</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Mismatched query and update of StringBuilder</problem_class>
|
||||
<description>Contents of StringBuilder <code>c</code> are updated, but never queried #loc</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+10
-4
@@ -1,10 +1,16 @@
|
||||
package com.siyeh.ig.bugs;
|
||||
|
||||
import com.siyeh.ig.IGInspectionTestCase;
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.siyeh.ig.LightInspectionTestCase;
|
||||
|
||||
public class MismatchedStringBuilderQueryUpdateInspectionTest extends IGInspectionTestCase {
|
||||
public class MismatchedStringBuilderQueryUpdateInspectionTest extends LightInspectionTestCase {
|
||||
|
||||
public void test() throws Exception {
|
||||
doTest("com/siyeh/igtest/bugs/mismatched_string_builder_query_update", new MismatchedStringBuilderQueryUpdateInspection());
|
||||
public void testMismatchedStringBuilderQueryUpdate() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
return new MismatchedStringBuilderQueryUpdateInspection();
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,12 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.xml.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.xml.DomFileElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.devkit.DevKitBundle;
|
||||
import org.jetbrains.idea.devkit.dom.Dependency;
|
||||
import org.jetbrains.idea.devkit.dom.IdeaPlugin;
|
||||
import org.jetbrains.idea.devkit.module.PluginModuleType;
|
||||
import org.jetbrains.idea.devkit.util.ActionType;
|
||||
import org.jetbrains.idea.devkit.util.ComponentType;
|
||||
@@ -62,7 +65,8 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool {
|
||||
|
||||
if (PluginModuleType.isOfType(module)) {
|
||||
return checkModule(module, psiClass, null, includeActions);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Set<PsiClass> types = null;
|
||||
final List<Module> modules = PluginModuleType.getCandidateModules(module);
|
||||
for (Module m : modules) {
|
||||
@@ -78,20 +82,26 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool {
|
||||
if (!DescriptorUtil.isPluginXml(pluginXml)) return types;
|
||||
assert pluginXml != null;
|
||||
|
||||
final XmlDocument document = pluginXml.getDocument();
|
||||
assert document != null;
|
||||
|
||||
final XmlTag rootTag = document.getRootTag();
|
||||
assert rootTag != null;
|
||||
|
||||
final String qualifiedName = psiClass.getQualifiedName();
|
||||
if (qualifiedName != null) {
|
||||
final RegistrationTypeFinder finder = new RegistrationTypeFinder(psiClass, types);
|
||||
|
||||
DescriptorUtil.processComponents(rootTag, finder);
|
||||
// "main" plugin.xml
|
||||
processPluginXml(pluginXml, finder, includeActions);
|
||||
|
||||
if (includeActions) {
|
||||
DescriptorUtil.processActions(rootTag, finder);
|
||||
// <depends> plugin.xml files
|
||||
final VirtualFile pluginXmlDirectory = pluginXml.getVirtualFile().getParent();
|
||||
final DomFileElement<IdeaPlugin> fileElement = DescriptorUtil.getIdeaPlugin(pluginXml);
|
||||
for (Dependency dependency : fileElement.getRootElement().getDependencies()) {
|
||||
final String configFile = dependency.getConfigFile().getValue();
|
||||
if (configFile != null) {
|
||||
final VirtualFile depVirtualFile = pluginXmlDirectory.findChild(configFile);
|
||||
if (depVirtualFile == null) continue;
|
||||
final PsiFile depPluginXml = PsiManager.getInstance(module.getProject()).findFile(depVirtualFile);
|
||||
if (DescriptorUtil.isPluginXml(depPluginXml)) {
|
||||
processPluginXml((XmlFile)depPluginXml, finder, includeActions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
types = finder.getTypes();
|
||||
@@ -100,6 +110,18 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool {
|
||||
return types;
|
||||
}
|
||||
|
||||
private static void processPluginXml(XmlFile xmlFile, RegistrationTypeFinder finder, boolean includeActions) {
|
||||
final XmlDocument document = xmlFile.getDocument();
|
||||
if (document == null) return;
|
||||
final XmlTag rootTag = document.getRootTag();
|
||||
if (rootTag == null) return;
|
||||
|
||||
DescriptorUtil.processComponents(rootTag, finder);
|
||||
if (includeActions) {
|
||||
DescriptorUtil.processActions(rootTag, finder);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static PsiElement getAttValueToken(@NotNull XmlAttribute attribute) {
|
||||
final XmlAttributeValue valueElement = attribute.getValueElement();
|
||||
@@ -132,13 +154,14 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool {
|
||||
return false;
|
||||
}
|
||||
|
||||
static class RegistrationTypeFinder implements ComponentType.Processor, ActionType.Processor {
|
||||
|
||||
private static class RegistrationTypeFinder implements ComponentType.Processor, ActionType.Processor {
|
||||
private Set<PsiClass> myTypes;
|
||||
private final String myQualifiedName;
|
||||
private final PsiManager myManager;
|
||||
private final GlobalSearchScope myScope;
|
||||
|
||||
public RegistrationTypeFinder(PsiClass psiClass, Set<PsiClass> types) {
|
||||
private RegistrationTypeFinder(PsiClass psiClass, Set<PsiClass> types) {
|
||||
myTypes = types;
|
||||
myQualifiedName = psiClass.getQualifiedName();
|
||||
myManager = psiClass.getManager();
|
||||
|
||||
@@ -87,7 +87,7 @@ public class DescriptorUtil {
|
||||
return getIdeaPlugin((XmlFile)file) != null;
|
||||
}
|
||||
|
||||
private static DomFileElement<IdeaPlugin> getIdeaPlugin(XmlFile file) {
|
||||
public static DomFileElement<IdeaPlugin> getIdeaPlugin(XmlFile file) {
|
||||
return DomManager.getDomManager(file.getProject()).getFileElement(file, IdeaPlugin.class);
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<idea-plugin>
|
||||
<actions>
|
||||
<action id="registeredAction" class="RegisteredAction"/>
|
||||
<action id="registeredInnerAction" class="RegisteredAction.InnerAction"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<idea-plugin>
|
||||
<!-- registeredActionInOptionalPluginDescriptor-optional-plugin.xml -->
|
||||
<depends optional="true" config-file="optional-plugin.xml"/>
|
||||
<depends optional="true" config-file="optional-plugin.xml"/>
|
||||
</idea-plugin>
|
||||
@@ -67,6 +67,14 @@ public class ComponentNotRegisteredInspectionTest extends LightCodeInsightFixtur
|
||||
myFixture.testHighlighting("RegisteredAction.java");
|
||||
}
|
||||
|
||||
public void testRegisteredActionInOptionalPluginDescriptor() {
|
||||
setPluginXml("registeredActionInOptionalPluginDescriptor-plugin.xml");
|
||||
myFixture.copyFileToProject("registeredActionInOptionalPluginDescriptor-optional-plugin.xml",
|
||||
"META-INF/optional-plugin.xml");
|
||||
|
||||
myFixture.testHighlighting("RegisteredAction.java");
|
||||
}
|
||||
|
||||
public void testUnregisteredAction() {
|
||||
setPluginXml("unregisteredAction-plugin.xml");
|
||||
myFixture.testHighlighting("UnregisteredAction.java");
|
||||
|
||||
Reference in New Issue
Block a user