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
.project
.Project
;
32 import com
.intellij
.openapi
.util
.Computable
;
33 import com
.intellij
.openapi
.util
.Pair
;
34 import com
.intellij
.openapi
.vfs
.VirtualFile
;
35 import com
.intellij
.util
.ArrayUtil
;
36 import com
.intellij
.util
.cls
.ClsFormatException
;
37 import com
.intellij
.util
.cls
.ClsUtil
;
38 import gnu
.trove
.TIntHashSet
;
39 import org
.jetbrains
.annotations
.NonNls
;
40 import org
.jetbrains
.annotations
.NotNull
;
41 import org
.jetbrains
.annotations
.Nullable
;
44 import java
.io
.IOException
;
45 import java
.rmi
.Remote
;
48 public class DependencyCache
{
49 private static final Logger LOG
= Logger
.getInstance("#com.intellij.compiler.make.DependencyCache");
51 private Cache myCache
;
52 private Cache myNewClassesCache
;
54 private static final String REMOTE_INTERFACE_NAME
= Remote
.class.getName();
55 private TIntHashSet myToUpdate
= new TIntHashSet(); // qName strings to be updated.
56 private final TIntHashSet myTraverseRoots
= new TIntHashSet(); // Dependencies are calculated from these clasess
57 private final TIntHashSet myClassesWithSourceRemoved
= new TIntHashSet();
58 private final TIntHashSet myPreviouslyRemoteClasses
= new TIntHashSet(); // classes that were Remote, but became non-Remote for some reason
59 private final TIntHashSet myMarkedInfos
= new TIntHashSet(); // classes to be recompiled
60 private final Set
<VirtualFile
> myMarkedFiles
= new HashSet
<VirtualFile
>();
62 private DependencyCacheNavigator myCacheNavigator
;
63 private SymbolTable mySymbolTable
;
64 private final String mySymbolTableFilePath
;
65 private final String myStoreDirectoryPath
;
66 @NonNls private static final String SYMBOLTABLE_FILE_NAME
= "symboltable.dat";
68 public DependencyCache(@NonNls String storeDirectoryPath
) {
69 myStoreDirectoryPath
= storeDirectoryPath
;
70 LOG
.assertTrue(myStoreDirectoryPath
!= null);
72 mySymbolTableFilePath
= myStoreDirectoryPath
+ "/" + SYMBOLTABLE_FILE_NAME
;
75 public DependencyCacheNavigator
getCacheNavigator() throws CacheCorruptedException
{
76 if (myCacheNavigator
== null) {
77 myCacheNavigator
= new DependencyCacheNavigator(getCache());
79 return myCacheNavigator
;
82 public void wipe() throws CacheCorruptedException
{
84 getNewClassesCache().wipe();
87 public Cache
getCache() throws CacheCorruptedException
{
89 if (myCache
== null) {
90 // base number of cached record views of each type
91 myCache
= new Cache(myStoreDirectoryPath
, 512);
96 catch (IOException e
) {
97 throw new CacheCorruptedException(e
);
101 public Cache
getNewClassesCache() throws CacheCorruptedException
{
103 if (myNewClassesCache
== null) {
104 myNewClassesCache
= new Cache(myStoreDirectoryPath
+ "/tmp", 16);
106 return myNewClassesCache
;
108 catch (IOException e
) {
109 throw new CacheCorruptedException(e
);
113 public void addTraverseRoot(int qName
) {
114 myTraverseRoots
.add(qName
);
117 public void clearTraverseRoots() {
118 myTraverseRoots
.clear();
121 public void markSourceRemoved(int qName
) {
122 myClassesWithSourceRemoved
.add(qName
);
125 public void addClassToUpdate(int qName
) {
126 myToUpdate
.add(qName
);
129 public int reparseClassFile(@NotNull File file
, final byte[] fileContent
) throws ClsFormatException
, CacheCorruptedException
{
130 SymbolTable symbolTable
= getSymbolTable();
132 final int qName
= getNewClassesCache().importClassInfo(new ClassFileReader(file
, symbolTable
, fileContent
), symbolTable
);
133 addClassToUpdate(qName
);
134 addTraverseRoot(qName
);
138 // for profiling purposes
140 private static void pause() {
141 System.out.println("PAUSED. ENTER A CHAR.");
142 byte[] buf = new byte[1];
146 catch (IOException e) {
152 public void update() throws CacheCorruptedException
{
153 if (myToUpdate
.isEmpty()) {
154 return; // optimization
157 final long updateStart
= System
.currentTimeMillis();
160 final int[] namesToUpdate
= myToUpdate
.toArray();
161 final Cache cache
= getCache();
162 final Cache newCache
= getNewClassesCache();
163 final DependencyCacheNavigator navigator
= getCacheNavigator();
165 // remove unnecesary dependencies
166 for (final int qName
: namesToUpdate
) {
167 // process use-dependencies
168 for (int referencedClassQName
: cache
.getReferencedClasses(qName
)) {
169 if (!cache
.containsClass(referencedClassQName
)) {
172 cache
.removeClassReferencer(referencedClassQName
, qName
);
174 cache
.clearReferencedClasses(qName
);
175 // process inheritance dependencies
176 navigator
.walkSuperClasses(qName
, new ClassInfoProcessor() {
177 public boolean process(int classQName
) throws CacheCorruptedException
{
178 cache
.removeSubclass(classQName
, qName
);
184 // do update of classInfos
185 for (final int qName
: namesToUpdate
) {
186 cache
.importClassInfo(newCache
, qName
);
189 // build forward-dependencies for the new infos, all new class infos must be already in the main cache!
191 final SymbolTable symbolTable
= getSymbolTable();
193 for (final int qName
: namesToUpdate
) {
194 if (!newCache
.containsClass(qName
)) {
197 buildForwardDependencies(qName
, newCache
.getReferences(qName
));
198 boolean isRemote
= false;
199 // "remote objects" are classes that _directly_ implement remote interfaces
200 final int[] superInterfaces
= cache
.getSuperInterfaces(qName
);
201 if (superInterfaces
.length
> 0) {
202 final int remoteInterfaceName
= symbolTable
.getId(REMOTE_INTERFACE_NAME
);
203 for (int superInterface
: superInterfaces
) {
204 if (isRemoteInterface(cache
, superInterface
, remoteInterfaceName
)) {
210 final boolean wasRemote
= cache
.isRemote(qName
);
211 if (wasRemote
&& !isRemote
) {
212 synchronized (myPreviouslyRemoteClasses
) {
213 myPreviouslyRemoteClasses
.add(qName
);
216 cache
.setRemote(qName
, isRemote
);
219 // building subclass dependencies
220 for (final int qName
: namesToUpdate
) {
221 buildSubclassDependencies(getCache(), qName
, qName
);
224 for (final int qName
: myClassesWithSourceRemoved
.toArray()) {
225 cache
.removeClass(qName
);
227 myToUpdate
= new TIntHashSet();
229 CompilerUtil
.logDuration("Dependency cache update", System
.currentTimeMillis() - updateStart
);
233 private void buildForwardDependencies(final int classQName
, final Collection
<ReferenceInfo
> references
) throws CacheCorruptedException
{
234 final Cache cache
= getCache();
236 final int genericSignature
= cache
.getGenericSignature(classQName
);
237 if (genericSignature
!= -1) {
238 final String genericClassSignature
= resolve(genericSignature
);
239 final int[] bounds
= findBounds(genericClassSignature
);
240 for (int boundClassQName
: bounds
) {
241 cache
.addClassReferencer(boundClassQName
, classQName
);
245 buildAnnotationDependencies(classQName
, cache
.getRuntimeVisibleAnnotations(classQName
));
246 buildAnnotationDependencies(classQName
, cache
.getRuntimeInvisibleAnnotations(classQName
));
248 for (final ReferenceInfo refInfo
: references
) {
249 final int declaringClassName
= getActualDeclaringClassForReference(refInfo
);
250 if (declaringClassName
== Cache
.UNKNOWN
) {
253 if (refInfo
instanceof MemberReferenceInfo
) {
254 final MemberInfo memberInfo
= ((MemberReferenceInfo
)refInfo
).getMemberInfo();
255 if (memberInfo
instanceof FieldInfo
) {
256 cache
.addFieldReferencer(declaringClassName
, memberInfo
.getName(), classQName
);
258 else if (memberInfo
instanceof MethodInfo
) {
259 cache
.addMethodReferencer(declaringClassName
, memberInfo
.getName(), memberInfo
.getDescriptor(), classQName
);
262 LOG
.error("Unknown member info class: " + memberInfo
.getClass().getName());
265 else { // reference to class
266 cache
.addClassReferencer(declaringClassName
, classQName
);
269 final SymbolTable symbolTable
= getSymbolTable();
271 for (final FieldInfo fieldInfo
: cache
.getFields(classQName
)) {
272 buildAnnotationDependencies(classQName
, fieldInfo
.getRuntimeVisibleAnnotations());
273 buildAnnotationDependencies(classQName
, fieldInfo
.getRuntimeInvisibleAnnotations());
275 String className
= MakeUtil
.parseObjectType(symbolTable
.getSymbol(fieldInfo
.getDescriptor()), 0);
276 if (className
== null) {
279 final int cls
= symbolTable
.getId(className
);
280 cache
.addClassReferencer(cls
, classQName
);
283 for (final MethodInfo methodInfo
: cache
.getMethods(classQName
)) {
284 buildAnnotationDependencies(classQName
, methodInfo
.getRuntimeVisibleAnnotations());
285 buildAnnotationDependencies(classQName
, methodInfo
.getRuntimeInvisibleAnnotations());
286 buildAnnotationDependencies(classQName
, methodInfo
.getRuntimeVisibleParameterAnnotations());
287 buildAnnotationDependencies(classQName
, methodInfo
.getRuntimeInvisibleParameterAnnotations());
289 if (methodInfo
.isConstructor()) {
293 final String returnTypeClassName
= MakeUtil
.parseObjectType(methodInfo
.getReturnTypeDescriptor(symbolTable
), 0);
294 if (returnTypeClassName
!= null) {
295 final int returnTypeClassQName
= symbolTable
.getId(returnTypeClassName
);
296 cache
.addClassReferencer(returnTypeClassQName
, classQName
);
299 String
[] parameterSignatures
= CacheUtils
.getParameterSignatures(methodInfo
, symbolTable
);
300 for (String parameterSignature
: parameterSignatures
) {
301 String paramClassName
= MakeUtil
.parseObjectType(parameterSignature
, 0);
302 if (paramClassName
!= null) {
303 final int paramClassId
= symbolTable
.getId(paramClassName
);
304 cache
.addClassReferencer(paramClassId
, classQName
);
310 private static boolean isRemoteInterface(Cache cache
, int ifaceName
, final int remoteInterfaceName
) throws CacheCorruptedException
{
311 if (ifaceName
== remoteInterfaceName
) {
314 for (int superInterfaceName
: cache
.getSuperInterfaces(ifaceName
)) {
315 if (isRemoteInterface(cache
, superInterfaceName
, remoteInterfaceName
)) {
323 private void buildAnnotationDependencies(int classQName
, AnnotationConstantValue
[][] annotations
) throws CacheCorruptedException
{
324 if (annotations
== null || annotations
.length
== 0) {
327 for (AnnotationConstantValue
[] annotation
: annotations
) {
328 buildAnnotationDependencies(classQName
, annotation
);
332 private void buildAnnotationDependencies(int classQName
, AnnotationConstantValue
[] annotations
) throws CacheCorruptedException
{
333 if (annotations
== null || annotations
.length
== 0) {
336 final Cache cache
= getCache();
337 for (AnnotationConstantValue annotation
: annotations
) {
338 final int annotationQName
= annotation
.getAnnotationQName();
340 cache
.addClassReferencer(annotationQName
, classQName
);
342 final AnnotationNameValuePair
[] memberValues
= annotation
.getMemberValues();
343 for (final AnnotationNameValuePair nameValuePair
: memberValues
) {
344 for (MethodInfo annotationMember
: cache
.findMethodsByName(annotationQName
, nameValuePair
.getName())) {
345 cache
.addMethodReferencer(annotationQName
, annotationMember
.getName(), annotationMember
.getDescriptor(), classQName
);
351 private int[] findBounds(final String genericClassSignature
) throws CacheCorruptedException
{
353 final String
[] boundInterfaces
= BoundsParser
.getBounds(genericClassSignature
);
354 int[] ids
= ArrayUtil
.newIntArray(boundInterfaces
.length
);
355 for (int i
= 0; i
< boundInterfaces
.length
; i
++) {
356 ids
[i
] = getSymbolTable().getId(boundInterfaces
[i
]);
360 catch (SignatureParsingException e
) {
361 return ArrayUtil
.EMPTY_INT_ARRAY
;
365 // fixes JDK 1.4 javac bug that generates references in the constant pool
366 // to the subclass even if the field was declared in a superclass
367 private int getActualDeclaringClassForReference(final ReferenceInfo refInfo
) throws CacheCorruptedException
{
368 if (!(refInfo
instanceof MemberReferenceInfo
)) {
369 return refInfo
.getClassName();
371 final int declaringClassName
= refInfo
.getClassName();
372 final Cache cache
= getCache();
373 final MemberInfo memberInfo
= ((MemberReferenceInfo
)refInfo
).getMemberInfo();
374 if (memberInfo
instanceof FieldInfo
) {
375 if (cache
.findFieldByName(declaringClassName
, memberInfo
.getName()) != null) {
376 return declaringClassName
;
379 else if (memberInfo
instanceof MethodInfo
) {
380 if (cache
.findMethod(declaringClassName
, memberInfo
.getName(), memberInfo
.getDescriptor()) != null) {
381 return declaringClassName
;
384 final DeclaringClassFinder finder
= new DeclaringClassFinder(memberInfo
);
385 getCacheNavigator().walkSuperClasses(declaringClassName
, finder
);
386 return finder
.getDeclaringClassName();
390 * @return qualified names of the classes that should be additionally recompiled
392 public Pair
<int[], Set
<VirtualFile
>> findDependentClasses(CompileContext context
, Project project
, Set
<VirtualFile
> successfullyCompiled
, @Nullable final DependencyProcessor additionalProcessor
)
393 throws CacheCorruptedException
{
395 markDependencies(context
, project
, successfullyCompiled
, additionalProcessor
);
396 return new Pair
<int[], Set
<VirtualFile
>>(myMarkedInfos
.toArray(), Collections
.unmodifiableSet(myMarkedFiles
));
399 private void markDependencies(CompileContext context
, Project project
, final Set
<VirtualFile
> successfullyCompiled
,
400 @Nullable final DependencyProcessor additionalProcessor
) throws CacheCorruptedException
{
402 if (LOG
.isDebugEnabled()) {
403 LOG
.debug("====================Marking dependent files=====================");
405 // myToUpdate can be modified during the mark procedure, so use toArray() to iterate it
406 final int[] traverseRoots
= myTraverseRoots
.toArray();
407 final SourceFileFinder sourceFileFinder
= new SourceFileFinder(project
, context
);
408 final CachingSearcher searcher
= new CachingSearcher(project
);
409 final ChangedRetentionPolicyDependencyProcessor changedRetentionPolicyDependencyProcessor
= new ChangedRetentionPolicyDependencyProcessor(project
, searcher
, this);
410 for (final int qName
: traverseRoots
) {
411 if (!getCache().containsClass(qName
)) {
414 if (getNewClassesCache().containsClass(qName
)) { // there is a new class file created
415 new JavaDependencyProcessor(project
, this, qName
).run();
416 ArrayList
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
> changed
=
417 new ArrayList
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
>();
418 ArrayList
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
> removed
=
419 new ArrayList
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
>();
420 findModifiedConstants(qName
, changed
, removed
);
421 if (!changed
.isEmpty() || !removed
.isEmpty()) {
422 new ChangedConstantsDependencyProcessor(
423 project
, searcher
, this, qName
,
424 changed
.toArray(new ChangedConstantsDependencyProcessor
.FieldChangeInfo
[changed
.size()]),
425 removed
.toArray(new ChangedConstantsDependencyProcessor
.FieldChangeInfo
[removed
.size()])
428 changedRetentionPolicyDependencyProcessor
.checkAnnotationRetentionPolicyChanges(qName
);
429 if (additionalProcessor
!= null) {
430 additionalProcessor
.processDependencies(context
, qName
);
434 boolean isSourceDeleted
= false;
435 if (myClassesWithSourceRemoved
.contains(qName
)) { // no recompiled class file, check whether the classfile exists
436 isSourceDeleted
= true;
438 else if (!new File(getCache().getPath(qName
)).exists()) {
439 final String qualifiedName
= resolve(qName
);
440 final String sourceFileName
= getCache().getSourceFileName(qName
);
441 final boolean markAsRemovedSource
= ApplicationManager
.getApplication().runReadAction(new Computable
<Boolean
>() {
442 public Boolean
compute() {
443 VirtualFile sourceFile
= sourceFileFinder
.findSourceFile(qualifiedName
, sourceFileName
);
444 return sourceFile
== null || successfullyCompiled
.contains(sourceFile
) ? Boolean
.TRUE
: Boolean
.FALSE
;
447 if (markAsRemovedSource
) {
448 // for Inner classes: sourceFile may exist, but the inner class declaration inside it may not,
449 // thus the source for the class info should be considered removed
450 isSourceDeleted
= true;
451 markSourceRemoved(qName
);
452 myMarkedInfos
.remove(qName
); // if the info has been marked already, the mark should be removed
455 if (isSourceDeleted
) {
456 Dependency
[] backDependencies
= getCache().getBackDependencies(qName
);
457 for (Dependency backDependency
: backDependencies
) {
458 if (markTargetClassInfo(backDependency
)) {
459 if (LOG
.isDebugEnabled()) {
461 "Mark dependent class " + backDependency
.getClassQualifiedName() + "; reason: no class file found for " + qName
);
468 if (LOG
.isDebugEnabled()) {
469 LOG
.debug("================================================================");
472 catch (ProcessCanceledException ignored
) {
473 // deliberately suppressed
477 private void findModifiedConstants(
479 Collection
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
> changedConstants
,
480 Collection
<ChangedConstantsDependencyProcessor
.FieldChangeInfo
> removedConstants
) throws CacheCorruptedException
{
482 final Cache cache
= getCache();
483 for (final FieldInfo field
: cache
.getFields(qName
)) {
484 final int oldFlags
= field
.getFlags();
485 if (ClsUtil
.isStatic(oldFlags
) && ClsUtil
.isFinal(oldFlags
)) {
486 final Cache newClassesCache
= getNewClassesCache();
487 FieldInfo newField
= newClassesCache
.findFieldByName(qName
, field
.getName());
488 if (newField
== null) {
489 if (!ConstantValue
.EMPTY_CONSTANT_VALUE
.equals(field
.getConstantValue())) {
490 // if the field was really compile time constant
491 removedConstants
.add(new ChangedConstantsDependencyProcessor
.FieldChangeInfo(field
));
495 final boolean visibilityRestricted
= MakeUtil
.isMoreAccessible(oldFlags
, newField
.getFlags());
496 if (!field
.getConstantValue().equals(newField
.getConstantValue()) || visibilityRestricted
) {
497 changedConstants
.add(new ChangedConstantsDependencyProcessor
.FieldChangeInfo(field
, visibilityRestricted
));
504 private static void buildSubclassDependencies(Cache cache
, final int qName
, int targetClassId
) throws CacheCorruptedException
{
505 final int superQName
= cache
.getSuperQualifiedName(targetClassId
);
506 if (superQName
!= Cache
.UNKNOWN
) {
507 cache
.addSubclass(superQName
, qName
);
508 buildSubclassDependencies(cache
, qName
, superQName
);
511 int[] interfaces
= cache
.getSuperInterfaces(targetClassId
);
512 for (final int interfaceName
: interfaces
) {
513 cache
.addSubclass(interfaceName
, qName
);
514 buildSubclassDependencies(cache
, qName
, interfaceName
);
520 * Marks ClassInfo targeted by the dependency
521 * @return true if really added, false otherwise
523 public boolean markTargetClassInfo(Dependency dependency
) throws CacheCorruptedException
{
524 return markClassInfo(dependency
.getClassQualifiedName(), false);
528 * Marks ClassInfo that corresponds to the specified qualified name
529 * If class info is already recompiled, it is not marked
530 * @return true if really added, false otherwise
532 public boolean markClass(int qualifiedName
) throws CacheCorruptedException
{
533 return markClass(qualifiedName
, false);
537 * Marks ClassInfo that corresponds to the specified qualified name
538 * If class info is already recompiled, it is not marked unless force parameter is true
539 * @return true if really added, false otherwise
541 public boolean markClass(int qualifiedName
, boolean force
) throws CacheCorruptedException
{
542 return markClassInfo(qualifiedName
, force
);
545 public boolean isTargetClassInfoMarked(Dependency dependency
) {
546 return isClassInfoMarked(dependency
.getClassQualifiedName());
549 public boolean isClassInfoMarked(int qName
) {
550 return myMarkedInfos
.contains(qName
);
553 public void markFile(VirtualFile file
) {
554 myMarkedFiles
.add(file
);
558 * @return true if really marked, false otherwise
560 private boolean markClassInfo(int qName
, boolean force
) throws CacheCorruptedException
{
561 if (!getCache().containsClass(qName
)) {
564 if (myClassesWithSourceRemoved
.contains(qName
)) {
565 return false; // no need to recompile since source has been removed
568 if (getNewClassesCache().containsClass(qName
)) { // already recompiled
572 return myMarkedInfos
.add(qName
);
575 public void resetState() {
576 final long start
= System
.currentTimeMillis();
579 myClassesWithSourceRemoved
.clear();
580 myMarkedFiles
.clear();
581 myMarkedInfos
.clear();
583 myTraverseRoots
.clear();
584 if (myNewClassesCache
!= null) {
585 myNewClassesCache
.wipe();
586 myNewClassesCache
= null;
588 myCacheNavigator
= null;
590 if (myCache
!= null) {
595 catch (CacheCorruptedException e
) {
599 if (mySymbolTable
!= null) {
600 mySymbolTable
.dispose();
601 mySymbolTable
= null;
604 catch (CacheCorruptedException e
) {
609 CompilerUtil
.logDuration("Dependency cache disposal", System
.currentTimeMillis() - start
);
614 public SymbolTable
getSymbolTable() throws CacheCorruptedException
{
615 if (mySymbolTable
== null) {
616 mySymbolTable
= new SymbolTable(new File(mySymbolTableFilePath
));
618 return mySymbolTable
;
621 public String
resolve(int id
) throws CacheCorruptedException
{
622 return getSymbolTable().getSymbol(id
);
625 public boolean wasRemote(int qName
) {
626 return myPreviouslyRemoteClasses
.contains(qName
);
629 private class DeclaringClassFinder
implements ClassInfoProcessor
{
630 private final int myMemberName
;
631 private final int myMemberDescriptor
;
632 private int myDeclaringClass
= Cache
.UNKNOWN
;
633 private final boolean myIsField
;
635 private DeclaringClassFinder(MemberInfo memberInfo
) {
636 myMemberName
= memberInfo
.getName();
637 myMemberDescriptor
= memberInfo
.getDescriptor();
638 myIsField
= memberInfo
instanceof FieldInfo
;
641 public int getDeclaringClassName() {
642 return myDeclaringClass
;
645 public boolean process(int classQName
) throws CacheCorruptedException
{
646 final Cache cache
= getCache();
648 final FieldInfo fieldId
= cache
.findField(classQName
, myMemberName
, myMemberDescriptor
);
649 if (fieldId
!= null) {
650 myDeclaringClass
= classQName
;
655 final MethodInfo methodId
= cache
.findMethod(classQName
, myMemberName
, myMemberDescriptor
);
656 if (methodId
!= null) {
657 myDeclaringClass
= classQName
;