@@ -7,17 +7,14 @@ import org.javacs.kt.util.filePath
7
7
import org.javacs.kt.util.describeURI
8
8
import org.javacs.kt.index.SymbolIndex
9
9
import org.javacs.kt.progress.Progress
10
- import org.javacs.kt.IndexingConfiguration
11
10
import com.intellij.lang.Language
12
- import com.intellij.psi.PsiFile
13
- import com.intellij.openapi.fileTypes.FileType
14
- import com.intellij.openapi.fileTypes.LanguageFileType
15
11
import org.jetbrains.kotlin.container.ComponentProvider
16
12
import org.jetbrains.kotlin.container.getService
17
13
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
18
14
import org.jetbrains.kotlin.psi.KtFile
19
15
import org.jetbrains.kotlin.resolve.BindingContext
20
16
import org.jetbrains.kotlin.resolve.CompositeBindingContext
17
+ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
21
18
import kotlin.concurrent.withLock
22
19
import java.nio.file.Path
23
20
import java.nio.file.Paths
@@ -33,7 +30,6 @@ class SourcePath(
33
30
private val parseDataWriteLock = ReentrantLock ()
34
31
35
32
private val indexAsync = AsyncExecutor ()
36
- private var indexInitialized: Boolean = false
37
33
var indexEnabled: Boolean by indexingConfig::enabled
38
34
val index = SymbolIndex ()
39
35
@@ -99,14 +95,16 @@ class SourcePath(
99
95
private fun doCompile () {
100
96
LOG .debug(" Compiling {}" , path?.fileName)
101
97
98
+ val oldFile = clone()
99
+
102
100
val (context, container) = cp.compiler.compileKtFile(parsed!! , allIncludingThis(), kind)
103
101
parseDataWriteLock.withLock {
104
102
compiledContext = context
105
103
compiledContainer = container
106
104
compiledFile = parsed
107
105
}
108
106
109
- initializeIndexAsyncIfNeeded(container )
107
+ refreshWorkspaceIndexes(listOfNotNull(oldFile), listOfNotNull( this ) )
110
108
}
111
109
112
110
private fun doCompileIfChanged () {
@@ -125,6 +123,9 @@ class SourcePath(
125
123
if (isTemporary) (all().asSequence() + sequenceOf(parsed!! )).toList()
126
124
else all()
127
125
}
126
+
127
+ // Creates a shallow copy
128
+ fun clone (): SourceFile = SourceFile (uri, content, path, parsed, compiledFile, compiledContext, compiledContainer, language, isTemporary)
128
129
}
129
130
130
131
private fun sourceFile (uri : URI ): SourceFile {
@@ -161,6 +162,8 @@ class SourcePath(
161
162
}
162
163
163
164
fun delete (uri : URI ) {
165
+ files[uri]?.let { refreshWorkspaceIndexes(listOf (it), listOf ()) }
166
+
164
167
files.remove(uri)
165
168
}
166
169
@@ -195,7 +198,20 @@ class SourcePath(
195
198
// Compile changed files
196
199
fun compileAndUpdate (changed : List <SourceFile >, kind : CompilationKind ): BindingContext ? {
197
200
if (changed.isEmpty()) return null
201
+
202
+ // Get clones of the old files, so we can remove the old declarations from the index
203
+ val oldFiles = changed.mapNotNull {
204
+ if (it.compiledFile?.text != it.content || it.parsed?.text != it.content) {
205
+ it.clone()
206
+ } else {
207
+ null
208
+ }
209
+ }
210
+
211
+ // Parse the files that have changed
198
212
val parse = changed.associateWith { it.apply { parseIfChanged() }.parsed!! }
213
+
214
+ // Get all the files. This will parse them if they changed
199
215
val allFiles = all()
200
216
beforeCompileCallback.invoke()
201
217
val (context, container) = cp.compiler.compileKtFiles(parse.values, allFiles, kind)
@@ -214,7 +230,7 @@ class SourcePath(
214
230
215
231
// Only index normal files, not build files
216
232
if (kind == CompilationKind .DEFAULT ) {
217
- initializeIndexAsyncIfNeeded(container )
233
+ refreshWorkspaceIndexes(oldFiles, parse.keys.toList() )
218
234
}
219
235
220
236
return context
@@ -230,18 +246,62 @@ class SourcePath(
230
246
return CompositeBindingContext .create(combined)
231
247
}
232
248
249
+ fun compileAllFiles () {
250
+ // TODO: Investigate the possibility of compiling all files at once, instead of iterating here
251
+ // At the moment, compiling all files at once sometimes leads to an internal error from the TopDownAnalyzer
252
+ files.keys.forEach {
253
+ compileFiles(listOf (it))
254
+ }
255
+ }
256
+
257
+ fun refreshDependencyIndexes () {
258
+ compileAllFiles()
259
+
260
+ val container = files.values.first { it.compiledContainer != null }.compiledContainer
261
+ if (container != null ) {
262
+ refreshDependencyIndexes(container)
263
+ }
264
+ }
265
+
233
266
/* *
234
- * Initialized the symbol index asynchronously, if not
235
- * already done.
267
+ * Refreshes the indexes. If already done, refreshes only the declarations in the files that were changed.
236
268
*/
237
- private fun initializeIndexAsyncIfNeeded (container : ComponentProvider ) = indexAsync.execute {
238
- if (indexEnabled && ! indexInitialized) {
239
- indexInitialized = true
269
+ private fun refreshWorkspaceIndexes (oldFiles : List <SourceFile >, newFiles : List <SourceFile >) = indexAsync.execute {
270
+ if (indexEnabled) {
271
+ val oldDeclarations = getDeclarationDescriptors(oldFiles)
272
+ val newDeclarations = getDeclarationDescriptors(newFiles)
273
+
274
+ // Index the new declarations in the Kotlin source files that were just compiled, removing the old ones
275
+ index.updateIndexes(oldDeclarations, newDeclarations)
276
+ }
277
+ }
278
+
279
+ /* *
280
+ * Refreshes the indexes. If already done, refreshes only the declarations in the files that were changed.
281
+ */
282
+ private fun refreshDependencyIndexes (container : ComponentProvider ) = indexAsync.execute {
283
+ if (indexEnabled) {
240
284
val module = container.getService(ModuleDescriptor ::class .java)
241
- index.refresh(module)
285
+ val declarations = getDeclarationDescriptors(files.values)
286
+ index.refresh(module, declarations)
242
287
}
243
288
}
244
289
290
+ // Gets all the declaration descriptors for the collection of files
291
+ private fun getDeclarationDescriptors (files : Collection <SourceFile >) =
292
+ files.flatMap { file ->
293
+ val compiledFile = file.compiledFile ? : file.parsed
294
+ val compiledContainer = file.compiledContainer
295
+ if (compiledFile != null && compiledContainer != null ) {
296
+ val module = compiledContainer.getService(ModuleDescriptor ::class .java)
297
+ module.getPackage(compiledFile.packageFqName).memberScope.getContributedDescriptors(
298
+ DescriptorKindFilter .ALL
299
+ ) { name -> compiledFile.declarations.map { it.name }.contains(name.toString()) }
300
+ } else {
301
+ listOf ()
302
+ }
303
+ }.asSequence()
304
+
245
305
/* *
246
306
* Recompiles all source files that are initialized.
247
307
*/
0 commit comments