2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * created at Jan 7, 2002
21 package com
.intellij
.compiler
.make
;
23 import com
.intellij
.compiler
.SymbolTable
;
24 import com
.intellij
.compiler
.classParsing
.*;
25 import com
.intellij
.compiler
.impl
.CompilerUtil
;
26 import com
.intellij
.compiler
.impl
.javaCompiler
.DependencyProcessor
;
27 import com
.intellij
.openapi
.application
.ApplicationManager
;
28 import com
.intellij
.openapi
.compiler
.CompileContext
;
29 import com
.intellij
.openapi
.diagnostic
.Logger
;
30 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
31 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
32 import com
.intellij
.openapi
.project
.Project
;
33 import com
.intellij
.openapi
.util
.Computable
;
34 import com
.intellij
.openapi
.util
.Pair
;
35 import com
.intellij
.openapi
.vfs
.VirtualFile
;
36 import com
.intellij
.util
.ArrayUtil
;
37 import com
.intellij
.util
.cls
.ClsFormatException
;
38 import com
.intellij
.util
.cls
.ClsUtil
;
39 import gnu
.trove
.TIntHashSet
;
40 import org
.jetbrains
.annotations
.NonNls
;
41 import org
.jetbrains
.annotations
.NotNull
;
42 import org
.jetbrains
.annotations
.Nullable
;
45 import java
.io
.IOException
;
46 import java
.rmi
.Remote
;
49 public class DependencyCache
{
50 private static final Logger LOG
= Logger
.getInstance("#com.intellij.compiler.make.DependencyCache");
52 private Cache myCache
;
53 private Cache myNewClassesCache
;
55 private static final String REMOTE_INTERFACE_NAME
= Remote
.class.getName();
56 private TIntHashSet myToUpdate
= new TIntHashSet(); // qName strings to be updated.
57 private final TIntHashSet myTraverseRoots
= new TIntHashSet(); // Dependencies are calculated from these clasess
58 private final TIntHashSet myClassesWithSourceRemoved
= new TIntHashSet();
59 private final TIntHashSet myPreviouslyRemoteClasses
= new TIntHashSet(); // classes that were Remote, but became non-Remote for some reason
60 private final TIntHashSet myMarkedInfos
= new TIntHashSet(); // classes to be recompiled
61 private final Set
<VirtualFile
> myMarkedFiles
= new HashSet
<VirtualFile
>();
63 private DependencyCacheNavigator myCacheNavigator
;
64 private SymbolTable mySymbolTable
;
65 private final String mySymbolTableFilePath
;
66 private final String myStoreDirectoryPath
;
67 @NonNls private static final String SYMBOLTABLE_FILE_NAME
= "symboltable.dat";
69 public DependencyCache(@NonNls String storeDirectoryPath
) {
70 myStoreDirectoryPath
= storeDirectoryPath
;
71 LOG
.assertTrue(myStoreDirectoryPath
!= null);
73 mySymbolTableFilePath
= myStoreDirectoryPath
+ "/" + SYMBOLTABLE_FILE_NAME
;
76 public DependencyCacheNavigator
getCacheNavigator() throws CacheCorruptedException
{
77 if (myCacheNavigator
== null) {
78 myCacheNavigator
= new DependencyCacheNavigator(getCache());
80 return myCacheNavigator
;
83 public void wipe() throws CacheCorruptedException
{
85 getNewClassesCache().wipe();
88 public Cache
getCache() throws CacheCorruptedException
{
90 if (myCache
== null) {
91 // base number of cached record views of each type
92 myCache
= new Cache(myStoreDirectoryPath
, 512);
97 catch (IOException e
) {
98 throw new CacheCorruptedException(e
);
102 public Cache
getNewClassesCache() throws CacheCorruptedException
{
104 if (myNewClassesCache
== null) {
105 myNewClassesCache
= new Cache(myStoreDirectoryPath
+ "/tmp", 16);
107 return myNewClassesCache
;
109 catch (IOException e
) {
110 throw new CacheCorruptedException(e
);
114 public void addTraverseRoot(int qName
) {
115 myTraverseRoots
.add(qName
);
118 public void clearTraverseRoots() {
119 myTraverseRoots
.clear();
122 public void markSourceRemoved(int qName
) {
123 myClassesWithSourceRemoved
.add(qName
);
126 public void addClassToUpdate(int qName
) {
127 myToUpdate
.add(qName
);
130 public int reparseClassFile(@NotNull File file
, final byte[] fileContent
) throws ClsFormatException
, CacheCorruptedException
{
131 SymbolTable symbolTable
= getSymbolTable();
133 final int qName
= getNewClassesCache().importClassInfo(new ClassFileReader(file
, symbolTable
, fileContent
), symbolTable
);
134 addClassToUpdate(qName
);
135 addTraverseRoot(qName
);
139 // for profiling purposes
141 private static void pause() {
142 System.out.println("PAUSED. ENTER A CHAR.");
143 byte[] buf = new byte[1];
147 catch (IOException e) {
153 public void update(ProgressIndicator indicator
) throws CacheCorruptedException
{
154 if (myToUpdate
.isEmpty()) {
155 return; // optimization
158 final long updateStart
= System
.currentTimeMillis();
161 final int[] namesToUpdate
= myToUpdate
.toArray();
162 final Cache cache
= getCache();
163 final Cache newCache
= getNewClassesCache();
164 final DependencyCacheNavigator navigator
= getCacheNavigator();
167 // remove unnecesary dependencies
168 for (final int qName
: namesToUpdate
) {
169 indicator
.setFraction(i
++*1.0/namesToUpdate
.length
/4);
170 // process use-dependencies
171 for (int referencedClassQName
: cache
.getReferencedClasses(qName
)) {
172 if (!cache
.containsClass(referencedClassQName
)) {
175 cache
.removeClassReferencer(referencedClassQName
, qName
);
177 cache
.clearReferencedClasses(qName
);
178 // process inheritance dependencies
179 navigator
.walkSuperClasses(qName
, new ClassInfoProcessor() {
180 public boolean process(int classQName
) throws CacheCorruptedException
{
181 cache
.removeSubclass(classQName
, qName
);
187 // do update of classInfos
188 for (final int qName
: namesToUpdate
) {
189 indicator
.setFraction(i
++*1.0/namesToUpdate
.length
/4);
190 cache
.importClassInfo(newCache
, qName
);
193 // build forward-dependencies for the new infos, all new class infos must be already in the main cache!
195 final SymbolTable symbolTable
= getSymbolTable();
197 for (final int qName
: namesToUpdate
) {
198 indicator
.setFraction(i
++*1.0/namesToUpdate
.length
/4);
199 if (!newCache
.containsClass(qName
)) {
202 buildForwardDependencies(qName
, newCache
.getReferences(qName
));
203 boolean isRemote
= false;
204 // "remote objects" are classes that _directly_ implement remote interfaces
205 final int[] superInterfaces
= cache
.getSuperInterfaces(qName
);
206 if (superInterfaces
.length
> 0) {
207 final int remoteInterfaceName
= symbolTable
.getId(REMOTE_INTERFACE_NAME
);
208 for (int superInterface
: superInterfaces
) {
209 if (isRemoteInterface(cache
, superInterface
, remoteInterfaceName
)) {
215 final boolean wasRemote
= cache
.isRemote(qName
);
216 if (wasRemote
&& !isRemote
) {
217 synchronized (myPreviouslyRemoteClasses
) {
218 myPreviouslyRemoteClasses
.add(qName
);
221 cache
.setRemote(qName
, isRemote
);
224 // building subclass dependencies
225 for (final int qName
: namesToUpdate
) {
226 indicator
.setFraction(i
++*1.0/namesToUpdate
.length
/4);
227 final int classId
= qName
;
228 buildSubclassDependencies(getCache(), qName
, classId
);
231 for (final int qName
: myClassesWithSourceRemoved
.toArray()) {
232 cache
.removeClass(qName
);
234 myToUpdate
= new TIntHashSet();
236 CompilerUtil
.logDuration("Dependency cache update", System
.currentTimeMillis() - updateStart
);
240 private void buildForwardDependencies(final int classQName
, final Collection
<ReferenceInfo
> references
) throws CacheCorruptedException
{
241 final Cache cache
= getCache();
243 final int genericSignature
= cache
.getGenericSignature(classQName
);
244 if (genericSignature
!= -1) {
245 final String genericClassSignature
= resolve(genericSignature
);
246 final int[] bounds
= findBounds(genericClassSignature
);
247 for (int boundClassQName
: bounds
) {
248 cache
.addClassReferencer(boundClassQName
, classQName
);
252 buildAnnotationDependencies(classQName
, cache
.getRuntimeVisibleAnnotations(classQName
));
253 buildAnnotationDependencies(classQName
, cache
.getRuntimeInvisibleAnnotations(classQName
));
255 for (final ReferenceInfo refInfo
: references
) {
256 final int declaringClassName
= getActualDeclaringClassForReference(refInfo
);
257 if (declaringClassName
== Cache
.UNKNOWN
) {
260 if (refInfo
instanceof MemberReferenceInfo
) {
261 final MemberInfo memberInfo
= ((MemberReferenceInfo
)refInfo
).getMemberInfo();
262 if (memberInfo
instanceof FieldInfo
) {
263 cache
.addFieldReferencer(declaringClassName
, memberInfo
.getName(), classQName
);
265 else if (memberInfo
instanceof MethodInfo
) {
266 cache
.addMethodReferencer(declaringClassName
, memberInfo
.getName(), memberInfo
.getDescriptor(), classQName
);
269 LOG
.error("Unknown member info class: " + memberInfo
.getClass().getName());
272 else { // reference to class
273 cache
.addClassReferencer(declaringClassName
, classQName
);
276 final SymbolTable symbolTable
= getSymbolTable();
278 for (final FieldInfo fieldInfo
: cache
.getFields(classQName
)) {
279 buildAnnotationDependencies(classQName
, fieldInfo
.getRuntimeVisibleAnnotations());
280 buildAnnotationDependencies(classQName
, fieldInfo
.getRuntimeInvisibleAnnotations());
282 String className
= MakeUtil
.parseObjectType(symbolTable
.getSymbol(fieldInfo
.getDescriptor()), 0);
283 if (className
== null) {
286 final int cls
= symbolTable
.getId(className
);
287 cache
.addClassReferencer(cls
, classQName
);
290 for (final MethodInfo methodInfo
: cache
.getMethods(classQName
)) {
291 buildAnnotationDependencies(classQName
, methodInfo
.getRuntimeVisibleAnnotations());
292 buildAnnotationDependencies(classQName
, methodInfo
.getRuntimeInvisibleAnnotations());
293 buildAnnotationDependencies(classQName
, methodInfo
.getRuntimeVisibleParameterAnnotations());
294 buildAnnotationDependencies(classQName
, methodInfo
.getRuntimeInvisibleParameterAnnotations());
296 if (methodInfo
.isConstructor()) {
300 final String returnTypeClassName
= MakeUtil
.parseObjectType(methodInfo
.getReturnTypeDescriptor(symbolTable
), 0);
301 if (returnTypeClassName
!= null) {
302 final int returnTypeClassQName
= symbolTable
.getId(returnTypeClassName
);
303 cache
.addClassReferencer(returnTypeClassQName
, classQName
);
306 String
[] parameterSignatures
= CacheUtils
.getParameterSignatures(methodInfo
, symbolTable
);
307 for (String parameterSignature
: parameterSignatures
) {
308 String paramClassName
= MakeUtil
.parseObjectType(parameterSignature
, 0);
309 if (paramClassName
!= null) {
310 final int paramClassId
= symbolTable
.getId(paramClassName
);
311 cache
.addClassReferencer(paramClassId
, classQName
);
317 private static boolean isRemoteInterface(Cache cache
, int ifaceName
, final int remoteInterfaceName
) throws CacheCorruptedException
{
318 if (ifaceName
== remoteInterfaceName
) {
321 for (int superInterfaceName
: cache
.getSuperInterfaces(ifaceName
)) {
322 if (isRemoteInterface(cache
, superInterfaceName
, remoteInterfaceName
)) {
330 private void buildAnnotationDependencies(int classQName
, AnnotationConstantValue
[][] annotations
) throws CacheCorruptedException
{
331 if (annotations
== null || annotations
.length
== 0) {
334 for (AnnotationConstantValue
[] annotation
: annotations
) {
335 buildAnnotationDependencies(classQName
, annotation
);
339 private void buildAnnotationDependencies(int classQName
, AnnotationConstantValue
[] annotations
) throws CacheCorruptedException
{
340 if (annotations
== null || annotations
.length
== 0) {
343 final Cache cache
= getCache();
344 for (AnnotationConstantValue annotation
: annotations
) {
345 final int annotationQName
= annotation
.getAnnotationQName();
347 cache
.addClassReferencer(annotationQName
, classQName
);
349 final AnnotationNameValuePair
[] memberValues
= annotation
.getMemberValues();
350 for (final AnnotationNameValuePair nameValuePair
: memberValues
) {
351 for (MethodInfo annotationMember
: cache
.findMethodsByName(annotationQName
, nameValuePair
.getName())) {
352 cache
.addMethodReferencer(annotationQName
, annotationMember
.getName(), annotationMember
.getDescriptor(), classQName
);
358 private int[] findBounds(final String genericClassSignature
) throws CacheCorruptedException
{
360 final String
[] boundInterfaces
= BoundsParser
.getBounds(genericClassSignature
);
361 int[] ids
= ArrayUtil
.newIntArray(boundInterfaces
.length
);
362 for (int i
= 0; i
< boundInterfaces
.length
; i
++) {
363 ids
[i
] = getSymbolTable().getId(boundInterfaces
[i
]);
367 catch (SignatureParsingException e
) {
368 return ArrayUtil
.EMPTY_INT_ARRAY
;
372 // fixes JDK 1.4 javac bug that generates references in the constant pool
373 // to the subclass even if the field was declared in a superclass
374 private int getActualDeclaringClassForReference(final ReferenceInfo refInfo
) throws CacheCorruptedException
{
375 if (!(refInfo
instanceof MemberReferenceInfo
)) {
376 return refInfo
.getClassName();
378 final int declaringClassName
= refInfo
.getClassName();
379 final Cache cache
= getCache();
380 final MemberInfo memberInfo
= ((MemberReferenceInfo
)refInfo
).getMemberInfo();
381 if (memberInfo
instanceof FieldInfo
) {
382 if (cache
.findFieldByName(declaringClassName
, memberInfo
.getName()) != null) {
383 return declaringClassName
;
386 else if (memberInfo
instanceof MethodInfo
) {
387 if (cache
.findMethod(declaringClassName
, memberInfo
.getName(), memberInfo
.getDescriptor()) != null) {
388 return declaringClassName
;
391 final DeclaringClassFinder finder
= new DeclaringClassFinder(memberInfo
);
392 getCacheNavigator().walkSuperClasses(declaringClassName
, finder
);
393 return finder
.getDeclaringClassName();
397 * @return qualified names of the classes that should be additionally recompiled
399 public Pair
<int[], Set
<VirtualFile
>> findDependentClasses(CompileContext context
, Project project
, Set
<VirtualFile
> successfullyCompiled
, @Nullable final DependencyProcessor additionalProcessor
)
400 throws CacheCorruptedException
{
402 markDependencies(context
, project
, successfullyCompiled
, additionalProcessor
);
403 return new Pair
<int[], Set
<VirtualFile
>>(myMarkedInfos
.toArray(), Collections
.unmodifiableSet(myMarkedFiles
));
406 private void markDependencies(CompileContext context
, Project project
, final Set
<VirtualFile
> successfullyCompiled
,
407 @Nullable final DependencyProcessor additionalProcessor
) throws CacheCorruptedException
{
409 if (LOG
.isDebugEnabled()) {
410 LOG
.debug("====================Marking dependent files=====================");
412 // myToUpdate can be modified during the mark procedure, so use toArray() to iterate it
413 int[] qNamesToUpdate
= myTraverseRoots
.toArray();
414 final SourceFileFinder sourceFileFinder
= new SourceFileFinder(project
, context
);
415 final CachingSearcher searcher
= new CachingSearcher(project
);
416 final ChangedRetentionPolicyDependencyProcessor changedRetentionPolicyDependencyProcessor
= new ChangedRetentionPolicyDependencyProcessor(project
, searcher
, this);
417 for (final int qName
: qNamesToUpdate
) {
418 if (!getCache().containsClass(qName
)) {
421 if (getNewClassesCache().containsClass(qName
)) { // there is a new class file created
422 new JavaDependencyProcessor(project
, this, qName
).run();
423 ArrayList
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
> changed
=
424 new ArrayList
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
>();
425 ArrayList
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
> removed
=
426 new ArrayList
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
>();
427 findModifiedConstants(qName
, changed
, removed
);
428 if (!changed
.isEmpty() || !removed
.isEmpty()) {
429 new ChangedConstantsDependencyProcessor(
430 project
, searcher
, this, qName
,
431 changed
.toArray(new ChangedConstantsDependencyProcessor
.FieldChangeInfo
[changed
.size()]),
432 removed
.toArray(new ChangedConstantsDependencyProcessor
.FieldChangeInfo
[removed
.size()])
435 changedRetentionPolicyDependencyProcessor
.checkAnnotationRetentionPolicyChanges(qName
);
436 if (additionalProcessor
!= null) {
437 additionalProcessor
.processDependencies(context
, qName
);
441 boolean isSourceDeleted
= false;
442 if (myClassesWithSourceRemoved
.contains(qName
)) { // no recompiled class file, check whether the classfile exists
443 isSourceDeleted
= true;
445 else if (!new File(getCache().getPath(qName
)).exists()) {
446 final String qualifiedName
= resolve(qName
);
447 final String sourceFileName
= getCache().getSourceFileName(qName
);
448 final boolean markAsRemovedSource
= ApplicationManager
.getApplication().runReadAction(new Computable
<Boolean
>() {
449 public Boolean
compute() {
450 VirtualFile sourceFile
= sourceFileFinder
.findSourceFile(qualifiedName
, sourceFileName
);
451 return sourceFile
== null || successfullyCompiled
.contains(sourceFile
) ? Boolean
.TRUE
: Boolean
.FALSE
;
454 if (markAsRemovedSource
) {
455 // for Inner classes: sourceFile may exist, but the inner class declaration inside it may not,
456 // thus the source for the class info should be considered removed
457 isSourceDeleted
= true;
458 markSourceRemoved(qName
);
459 myMarkedInfos
.remove(qName
); // if the info has been marked already, the mark should be removed
462 if (isSourceDeleted
) {
463 Dependency
[] backDependencies
= getCache().getBackDependencies(qName
);
464 for (Dependency backDependency
: backDependencies
) {
465 if (markTargetClassInfo(backDependency
)) {
466 if (LOG
.isDebugEnabled()) {
468 "Mark dependent class " + backDependency
.getClassQualifiedName() + "; reason: no class file found for " + qName
);
475 if (LOG
.isDebugEnabled()) {
476 LOG
.debug("================================================================");
479 catch (ProcessCanceledException ignored
) {
480 // deliberately suppressed
484 private void findModifiedConstants(
486 Collection
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
> changedConstants
,
487 Collection
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
> removedConstants
) throws CacheCorruptedException
{
489 final Cache cache
= getCache();
490 for (final FieldInfo field
: cache
.getFields(qName
)) {
491 final int oldFlags
= field
.getFlags();
492 if (ClsUtil
.isStatic(oldFlags
) && ClsUtil
.isFinal(oldFlags
)) {
493 final Cache newClassesCache
= getNewClassesCache();
494 FieldInfo newField
= newClassesCache
.findFieldByName(qName
, field
.getName());
495 if (newField
== null) {
496 if (!ConstantValue
.EMPTY_CONSTANT_VALUE
.equals(field
.getConstantValue())) {
497 // if the field was really compile time constant
498 removedConstants
.add(new ChangedConstantsDependencyProcessor
.FieldChangeInfo(field
));
502 final boolean visibilityRestricted
= MakeUtil
.isMoreAccessible(oldFlags
, newField
.getFlags());
503 if (!field
.getConstantValue().equals(newField
.getConstantValue()) || visibilityRestricted
) {
504 changedConstants
.add(new ChangedConstantsDependencyProcessor
.FieldChangeInfo(field
, visibilityRestricted
));
511 private static void buildSubclassDependencies(Cache cache
, final int qName
, int targetClassId
) throws CacheCorruptedException
{
512 final int superQName
= cache
.getSuperQualifiedName(targetClassId
);
513 if (superQName
!= Cache
.UNKNOWN
) {
514 cache
.addSubclass(superQName
, qName
);
515 buildSubclassDependencies(cache
, qName
, superQName
);
518 int[] interfaces
= cache
.getSuperInterfaces(targetClassId
);
519 for (final int interfaceName
: interfaces
) {
520 cache
.addSubclass(interfaceName
, qName
);
521 buildSubclassDependencies(cache
, qName
, interfaceName
);
527 * Marks ClassInfo targeted by the dependency
528 * @return true if really added, false otherwise
530 public boolean markTargetClassInfo(Dependency dependency
) throws CacheCorruptedException
{
531 return markClassInfo(dependency
.getClassQualifiedName(), false);
535 * Marks ClassInfo that corresponds to the specified qualified name
536 * If class info is already recompiled, it is not marked
537 * @return true if really added, false otherwise
539 public boolean markClass(int qualifiedName
) throws CacheCorruptedException
{
540 return markClass(qualifiedName
, false);
544 * Marks ClassInfo that corresponds to the specified qualified name
545 * If class info is already recompiled, it is not marked unless force parameter is true
546 * @return true if really added, false otherwise
548 public boolean markClass(int qualifiedName
, boolean force
) throws CacheCorruptedException
{
549 return markClassInfo(qualifiedName
, force
);
552 public boolean isTargetClassInfoMarked(Dependency dependency
) {
553 return isClassInfoMarked(dependency
.getClassQualifiedName());
556 public boolean isClassInfoMarked(int qName
) {
557 return myMarkedInfos
.contains(qName
);
560 public void markFile(VirtualFile file
) {
561 myMarkedFiles
.add(file
);
565 * @return true if really marked, false otherwise
567 private boolean markClassInfo(int qName
, boolean force
) throws CacheCorruptedException
{
568 if (!getCache().containsClass(qName
)) {
571 if (myClassesWithSourceRemoved
.contains(qName
)) {
572 return false; // no need to recompile since source has been removed
575 if (getNewClassesCache().containsClass(qName
)) { // already recompiled
579 return myMarkedInfos
.add(qName
);
582 public void resetState() {
583 final long start
= System
.currentTimeMillis();
586 myClassesWithSourceRemoved
.clear();
587 myMarkedFiles
.clear();
588 myMarkedInfos
.clear();
590 myTraverseRoots
.clear();
591 if (myNewClassesCache
!= null) {
592 myNewClassesCache
.wipe();
593 myNewClassesCache
= null;
595 myCacheNavigator
= null;
597 if (myCache
!= null) {
602 catch (CacheCorruptedException e
) {
606 if (mySymbolTable
!= null) {
607 mySymbolTable
.dispose();
608 mySymbolTable
= null;
611 catch (CacheCorruptedException e
) {
616 CompilerUtil
.logDuration("Dependency cache disposal", System
.currentTimeMillis() - start
);
621 public SymbolTable
getSymbolTable() throws CacheCorruptedException
{
622 if (mySymbolTable
== null) {
623 mySymbolTable
= new SymbolTable(new File(mySymbolTableFilePath
));
625 return mySymbolTable
;
628 public String
resolve(int id
) throws CacheCorruptedException
{
629 return getSymbolTable().getSymbol(id
);
632 public boolean wasRemote(int qName
) {
633 return myPreviouslyRemoteClasses
.contains(qName
);
636 private class DeclaringClassFinder
implements ClassInfoProcessor
{
637 private final int myMemberName
;
638 private final int myMemberDescriptor
;
639 private int myDeclaringClass
= Cache
.UNKNOWN
;
640 private final boolean myIsField
;
642 private DeclaringClassFinder(MemberInfo memberInfo
) {
643 myMemberName
= memberInfo
.getName();
644 myMemberDescriptor
= memberInfo
.getDescriptor();
645 myIsField
= memberInfo
instanceof FieldInfo
;
648 public int getDeclaringClassName() {
649 return myDeclaringClass
;
652 public boolean process(int classQName
) throws CacheCorruptedException
{
653 final Cache cache
= getCache();
655 final FieldInfo fieldId
= cache
.findField(classQName
, myMemberName
, myMemberDescriptor
);
656 if (fieldId
!= null) {
657 myDeclaringClass
= classQName
;
662 final MethodInfo methodId
= cache
.findMethod(classQName
, myMemberName
, myMemberDescriptor
);
663 if (methodId
!= null) {
664 myDeclaringClass
= classQName
;