0001: package Schmortopf.JavaSourceEditor.SymbolUsageLocationSearch;
0002:
0003: /**
0004: * Searches all locations, where a given symbol is used.
0005: * A symbol can be:
0006: * - a method,
0007: * - a class or member attribute,
0008: * - a given fully qualified classname [ -> search for instantiations ]
0009: *
0010: * Operation:
0011: *
0012: * This process uses the results of the file ***dependencies scanner***:
0013: * One only has to search files, which have the source file containing the
0014: * symbol in their dependency-files-list.
0015: * Or short: Only look in files, which depend in some way from the
0016: * file containing the given symbol.
0017: *
0018: * For each **possible** candidate [entry in some "Block" parsertree node],
0019: * one must follow the trace through possible
0020: * parents tree's back (like done, when the user clicks on
0021: * "Jump to declaration" - just do the same and see, the target really is
0022: * the file containing the given symbol. If this is the case, one usage
0023: * location has been found and can be added to a list.
0024: *
0025: */
0026:
0027: import java.util.Vector;
0028: import java.awt.EventQueue;
0029: import java.awt.Point;
0030: import java.io.CharArrayReader;
0031: import javax.swing.JOptionPane;
0032: import javax.swing.tree.DefaultMutableTreeNode;
0033:
0034: import Schmortopf.Main.IDE_ProjectFrame;
0035: import Schmortopf.FileStructure.FileStructureDescriptionManager;
0036: import Schmortopf.FileStructure.FileStructureDescriptionParserTreePostProcessor;
0037: import Schmortopf.FileStructure.Descriptions.*;
0038: import Schmortopf.JavaSourceEditor.SourceEditorDocument;
0039: import Schmortopf.JavaSourceEditor.TextSearch.*;
0040: import Schmortopf.JavaLanguageParser.*;
0041: import Schmortopf.JavaLanguageParser.JavaCCParser.*;
0042: import Schmortopf.FileComponents.Model.TokenTreeUserObject;
0043: import Schmortopf.FileComponents.Model.EditableLeafObject;
0044: import Schmortopf.FileComponents.View.FileComponentsTreeCellRenderer;
0045: import Schmortopf.JavaSourceEditor.TextSearch.ObjectSearch;
0046: import Schmortopf.SearchResults.SearchResultsUserObject;
0047: import Schmortopf.Utility.StringUtilities;
0048: import Schmortopf.Utility.ThreadEngine.ThreadEngine;
0049: import Schmortopf.Utility.gui.dialogs.ProgressWindow;
0050: import Schmortopf.JavaSourceEditor.CodeCompletion.CodeCompletionUtilities;
0051: import Language.Language;
0052: import Shared.Logging.Log;
0053:
0054: public class SymbolUsageLocationSearch implements
0055: ParserOutputProcessor, JavaParserConstants {
0056:
0057: private IDE_ProjectFrame projectFrame;
0058: private ParserTreeNode currentNode; // used by the java parser
0059:
0060: private final String searchMessage = Language
0061: .Translate("Searching")
0062: + "...";
0063: private final String searchInfoMessage = Language
0064: .Translate("The results are displayed in the search results tree.");
0065:
0066: private boolean searchHasBeenCancelledByTheUser = false;
0067:
0068: public SymbolUsageLocationSearch(IDE_ProjectFrame theProjectFrame) {
0069: this .projectFrame = theProjectFrame;
0070: } // Constructor
0071:
0072: /**
0073: * Search all locations inside the project,
0074: * where the classes passed in selectedTargetFSDs are used.
0075: */
0076: public void searchClassUsageLocationsFor(
0077: final FileStructureDescription[] selectedTargetFSDs,
0078: final boolean doTrackAttributes) {
0079: // Wait until the other popups have goone, so the
0080: // way is cleared for a new progresswindow:
0081: EventQueue.invokeLater(new Runnable() {
0082: public void run() {
0083: // We must call the dependencies updater and tell it to process all
0084: // pending entries. For this and other reasons, we must process this
0085: // in a user thread, otherwise one could produce deadlocks:
0086: Runnable searchRunnable = new Runnable() {
0087: public void run() {
0088: // Give Swing some time right now (to show the progressWindow):
0089: //try{ Thread.sleep(1199); } catch( Exception e2 ){}
0090: searchClassUsageLocations_InThread(
0091: selectedTargetFSDs, doTrackAttributes);
0092: }
0093: };
0094: ThreadEngine.getInstance().addRunnable(searchRunnable,
0095: "searchClassUsageLocationsFor");
0096: }
0097: });
0098: } // searchClassUsageLocationsFor
0099:
0100: /**
0101: * Search all locations inside the project,
0102: * where the classes passed in selectedTargetFSDs are used.
0103: */
0104: private void searchClassUsageLocations_InThread(
0105: final FileStructureDescription[] selectedTargetFSDs,
0106: final boolean doTrackAttributes) {
0107: searchHasBeenCancelledByTheUser = false; // initialize
0108: String searchName = "Class"; // is displayed as tab title in the search results panel
0109: // Make sure, the searchresults tree displays some useful information
0110: // while the search is running, and reset it, if the search didn't find anything.
0111: this .projectFrame.initializeSearchResults(searchName,
0112: searchMessage);
0113: // Give Swing some time right now:
0114: try {
0115: Thread.sleep(44);
0116: } catch (Exception e0) {
0117: }
0118: // Call the actual worker method:
0119: boolean elementsHaveBeenFound = this
0120: .search_Class_Usage_Locations_In_Thread(searchName,
0121: selectedTargetFSDs, doTrackAttributes);
0122: if (!elementsHaveBeenFound) {
0123: // Signalize it's ready for new searches:
0124: this .projectFrame.initializeSearchResults(searchName,
0125: Language.Translate("No hits"));
0126: // Give Swing some time right now:
0127: try {
0128: Thread.sleep(44);
0129: } catch (Exception e2) {
0130: }
0131: }
0132: } // searchClassUsageLocations_InThread
0133:
0134: /**
0135: * Search all locations inside the project,
0136: * where the classes passed in selectedTargetFSDs are used.
0137: */
0138: private boolean search_Class_Usage_Locations_In_Thread(
0139: final String searchName,
0140: final FileStructureDescription[] selectedTargetFSDs,
0141: final boolean doTrackAttributes) {
0142:
0143: //ystem.out.println("cc> search_Class_Usage_Locations_In_Thread starts.");
0144: //ystem.out.println("cc> selectedTargetFSDs.length= " + selectedTargetFSDs.length );
0145:
0146: boolean elementsHaveBeenFound = false;
0147: long startTime = System.currentTimeMillis();
0148: // Make the progressWindow and show it, if the search
0149: // has package or global scope, otherwise the search is so fast,
0150: // that the progressWindow is not needed:
0151: ProgressWindow progressWindowCandidate = null;
0152: String windowText = searchMessage + "\n" + searchInfoMessage;
0153: progressWindowCandidate = new ProgressWindow(windowText, null,
0154: projectFrame.getParentFrameForChildren(), projectFrame
0155: .getMainFrameProvider(), true);
0156: progressWindowCandidate.showCentered();
0157:
0158: final ProgressWindow progressWindow = progressWindowCandidate;
0159:
0160: FileStructureDescriptionManager fsdManager = this .projectFrame
0161: .getFileStructureDescriptionManager();
0162: // We need the file dependencies list to be complete, so tell the
0163: // dependencies updater to process all pending entries right now.
0164: // The pc must be in a user thread context for this.
0165: fsdManager.waitForUpdaters();
0166:
0167: // In contrary to the other two searches [ attribute and method usage search ]
0168: // this search just can be carries out by making one search for each element
0169: // in the selectedTargetFSDs and adding the hits:
0170: // Fill all hits into ClassReferenceEntry objects and add them to this vector:
0171: Vector classReferences = new Vector();
0172: for (int targetFSDIndex = 0; targetFSDIndex < selectedTargetFSDs.length; targetFSDIndex++) {
0173: final FileStructureDescription targetFSD = selectedTargetFSDs[targetFSDIndex];
0174: searchClassUsageLocationsOf(
0175: selectedTargetFSDs[targetFSDIndex],
0176: classReferences, fsdManager, doTrackAttributes,
0177: progressWindow);
0178: if (progressWindow != null) {
0179: // Break the search, if the user has pushed the cancel button:
0180: if (progressWindow.getWasCancelled()) {
0181: searchHasBeenCancelledByTheUser = true;
0182: break;
0183: }
0184: try {
0185: Thread.yield();
0186: } catch (Exception e234986) {
0187: }
0188: }
0189: } // for loop for each selectedTargetFSDs element
0190:
0191: if (!this .searchHasBeenCancelledByTheUser) {
0192: // Not absolutely required, but more secure, because at least the queue of the
0193: // dependency updater will contain some entries: Force to perform all pending
0194: // entries again:
0195: fsdManager.waitForUpdaters();
0196:
0197: if (progressWindow != null) {
0198: final int maxValue = classReferences.size();
0199: EventQueue.invokeLater(new Runnable() {
0200: public void run() {
0201: progressWindow.setProgressValue(0);
0202: progressWindow.setProgressMaxValue(maxValue);
0203: }
0204: });
0205: }
0206:
0207: // Create the SearchResultsUserObject vector:
0208: Vector searchResultsUserObjectVector = new Vector();
0209: for (int i = 0; i < classReferences.size(); i++) {
0210:
0211: if (progressWindow != null) {
0212: final int progressValue = i;
0213: EventQueue.invokeLater(new Runnable() {
0214: public void run() {
0215: progressWindow
0216: .setProgressValue(progressValue);
0217: }
0218: });
0219: // Break the search, if the user has pushed the cancel button:
0220: if (progressWindow.getWasCancelled()) {
0221: searchHasBeenCancelledByTheUser = true;
0222: break;
0223: }
0224: try {
0225: Thread.yield();
0226: } catch (Exception e234986) {
0227: }
0228: }
0229:
0230: final ClassReferenceEntry entry = (ClassReferenceEntry) classReferences
0231: .elementAt(i);
0232: // We need the SourceEditorDocument:
0233: EditableLeafObject leaf = fsdManager
0234: .getJavaSourceEditorLeafForFSD(entry
0235: .getParentFSD());
0236: // On leaf level, one should unload the content, after having loaded and processed it.
0237: // But one shouldn't unload it, if it already was loaded by another one, when this method starts.
0238: // It's not serious, if this doesn't work some times, so no need for synchronization here.
0239: boolean leafWasLoadedInitially = leaf.isContentLoaded();
0240: Object leafContent = leaf.getContent();
0241: if (leafContent instanceof SourceEditorDocument) {
0242: final SourceEditorDocument sourceDoc = (SourceEditorDocument) leafContent;
0243:
0244: // Create a SearchResultsFileNodeUserObject and add it to the vector:
0245: final int docPosition = sourceDoc
0246: .getPositionOfStartOfLine(entry
0247: .getStartLine() - 1)
0248: + (entry.getStartColumn() + entry
0249: .getEndColumn()) / 2;
0250: final boolean breakAtPoints = false;
0251: final int[] nearestWordPosition = sourceDoc
0252: .getNearestWordPositionTo(docPosition,
0253: breakAtPoints);
0254: final int startOffset = nearestWordPosition[0];
0255: final int endOffset = nearestWordPosition[1];
0256:
0257: final SearchResultsUserObject resultUserObject = new SearchResultsUserObject(
0258: leaf, entry.getStartLine() - 1,
0259: docPosition, entry.getEndColumn()
0260: - entry.getStartColumn() + 1);
0261:
0262: searchResultsUserObjectVector
0263: .addElement(resultUserObject);
0264: } // if
0265: else {
0266: Log
0267: .Error("leafContent as NOT instanceof SourceEditorDocument");
0268: }
0269: // Be careful with unloading: One only is allowed to unload the leaf,
0270: // if it has not been loaded, when this method has started, otherwise we could
0271: // possibly unload a leaf, which currently is displayed in the editor, which
0272: // would cause the editor to crash soon after this.
0273: if (!leafWasLoadedInitially) {
0274: leaf.unloadContent(false); // make memory of this available sooner (gc)
0275: }
0276: } // for
0277:
0278: /*
0279: long elapsedTime = System.currentTimeMillis() - startTime;
0280: Log.Info("cc> elapsedTime= " + elapsedTime );
0281: Log.Info("cc> CheckResults: Found " + searchResultsUserObjectVector.size() + " hits.");
0282: */
0283:
0284: // Close and dipose the progressWindow, if it has been created:
0285: if (progressWindow != null) {
0286: EventQueue.invokeLater(new Runnable() {
0287: public void run() {
0288: progressWindow.setVisible(false);
0289: progressWindow.dispose();
0290: }
0291: });
0292: // Give Swing some time right now:
0293: try {
0294: Thread.sleep(88);
0295: } catch (Exception e1) {
0296: }
0297: } // if
0298:
0299: // Tell the searchresults tree to display action-entries for the
0300: // found results, if some were found:
0301: if (searchResultsUserObjectVector.size() > 0) {
0302: elementsHaveBeenFound = true;
0303: SearchResultsUserObject[] searchResultsUserObjects = new SearchResultsUserObject[searchResultsUserObjectVector
0304: .size()];
0305: searchResultsUserObjectVector
0306: .copyInto(searchResultsUserObjects);
0307: this .projectFrame
0308: .setSearchResultsTreeContentWithObjectSearchResults(
0309: searchName, searchResultsUserObjects);
0310: } else {
0311: String title = Language
0312: .Translate("Object Search Results");
0313: String message = Language
0314: .Translate("The object search hasn't found any results.");
0315: JOptionPane
0316: .showMessageDialog(this .projectFrame, message,
0317: title, JOptionPane.INFORMATION_MESSAGE);
0318: }
0319: classReferences.setSize(0); // GC assistance
0320: } // if th search has not been cancelled by the user
0321: else {
0322: // Close and dipose the progressWindow, if it has been created:
0323: if (progressWindow != null) {
0324: EventQueue.invokeLater(new Runnable() {
0325: public void run() {
0326: progressWindow.setVisible(false);
0327: progressWindow.dispose();
0328: }
0329: });
0330: // Give Swing some time right now:
0331: try {
0332: Thread.sleep(88);
0333: } catch (Exception e1) {
0334: }
0335: } // if
0336: } // else
0337:
0338: //ystem.out.println("cc> search_Class_Usage_Locations_In_Thread ends.");
0339:
0340: return elementsHaveBeenFound;
0341: } // searchClassUsageLocations_InThread
0342:
0343: /**
0344: * Add all found usages of basisFSD anywhere in the project
0345: * in ClassReferenceEntry objects to the classReferences vetcor.
0346: */
0347: private void searchClassUsageLocationsOf(
0348: final FileStructureDescription basisFSD,
0349: final Vector classReferences,
0350: final FileStructureDescriptionManager fsdManager,
0351: final boolean doTrackAttributes,
0352: final ProgressWindow progressWindow) {
0353:
0354: //ystem.out.println("cc> searchClassUsageLocationsOf " +
0355: // basisFSD.fullyQualifiedClassNameBuffer.toString() +
0356: // " starts." );
0357:
0358: // Search references to classFSD in all classes, which have a dependency
0359: // to classFSD:
0360: Vector dependentFSDs = new Vector();
0361: // Add all files, which depend from the basisFSD
0362: // and any project class and its dependent classes in the parent chain:
0363: this .addAllFSDsWhichDependFrom(basisFSD, dependentFSDs,
0364: fsdManager);
0365:
0366: //ystem.out.println("cc> searchClassUsageLocationsOf: " +
0367: // dependentFSDs.size() +
0368: // " dependent classes have been found." );
0369:
0370: // Parse each class of the dependentFSDs and examine the java tree:
0371: FileStructureDescriptionParserTreePostProcessor postProcessor = new FileStructureDescriptionParserTreePostProcessor(
0372: fsdManager);
0373:
0374: if (progressWindow != null) {
0375: progressWindow.setProgressMaxValue(dependentFSDs.size());
0376: }
0377:
0378: if (!this .searchHasBeenCancelledByTheUser) {
0379: // Fill all hits into ClassReferenceEntry objects and add them to this vector:
0380: for (int fsdIndex = 0; fsdIndex < dependentFSDs.size(); fsdIndex++) {
0381:
0382: if (progressWindow != null) {
0383: final int progressValue = fsdIndex;
0384: EventQueue.invokeLater(new Runnable() {
0385: public void run() {
0386: progressWindow
0387: .setProgressValue(progressValue);
0388: }
0389: });
0390: // Break the search, if the user has pushed the cancel button:
0391: if (progressWindow.getWasCancelled()) {
0392: searchHasBeenCancelledByTheUser = true;
0393: break;
0394: }
0395: try {
0396: Thread.yield();
0397: } catch (Exception e234986) {
0398: }
0399: }
0400:
0401: final FileStructureDescription candidateFSD = (FileStructureDescription) dependentFSDs
0402: .elementAt(fsdIndex);
0403: // Get the associated source text (can be from java files or from jar archives)
0404: final StringBuffer candidateSourceCode = fsdManager
0405: .getJavaSourceForFSD(candidateFSD);
0406: // Get the full parser tree:
0407: final ParserTreeNode compilationUnitNode = this
0408: .getCompilationUnitNodeFor(
0409: candidateSourceCode,
0410: candidateFSD.fullyQualifiedClassNameBuffer
0411: .toString());
0412: // For the following scan, the fsd must have the local fields, which usually only
0413: // are parsed for fsd's of sources, which are going to be displayed in the source editor.
0414: // This actions here are made for many fsd's, which of course are not displayed in
0415: // the editor, so we have to update them to have the local fields information:
0416: // Note the two flags:
0417: // create local fields = true ( as mentionned above )
0418: // call dependency scanner = true : Because the dependency fields are cleared
0419: // by the postProcessor, the dependencies
0420: // ALWAYS must be recalculated.
0421: // Because the postprocessor stores
0422: // the compilationrootnode and the fsd in the entries
0423: // sent to the dependency updater, this doesn't
0424: // cost much time:
0425: // This all is done on the same fsd reference.
0426: postProcessor.updatePostProcessParserTree(candidateFSD,
0427: candidateFSD.belongsToProject,
0428: compilationUnitNode,
0429: candidateFSD.pathNameBuffer.toString(), true, /*create local fields*/
0430: true /*call dependency scanner*/);
0431: // Now deepscan the tree for finding locations where an object of class given by
0432: // the basisFSD is created or explicitly used in objects or in cast expressions.
0433: this .scanForClassUsage(candidateFSD,
0434: compilationUnitNode,
0435: basisFSD.fullyQualifiedClassNameBuffer
0436: .toString(), classReferences,
0437: doTrackAttributes);
0438: } // for fsdIndex
0439: } // if
0440:
0441: //ystem.out.println("cc> searchClassUsageLocationsOf " +
0442: // basisFSD.fullyQualifiedClassNameBuffer.toString() +
0443: // " ends." );
0444:
0445: } // searchClassUsageLocationsOf
0446:
0447: /**
0448: * Scan the javaCCBasisNode (created from the candidateFSD)
0449: * for object creation of a class given by
0450: * searchedFullyQualifiedClassName, or declaration of attributes or
0451: * explicit type casts of this class.
0452: * Each found location is passed to a ClassReferenceEntry object
0453: * and added to the classReferences vector.
0454: */
0455: private void scanForClassUsage(
0456: final FileStructureDescription candidateFSD,
0457: final DefaultMutableTreeNode javaCCBasisNode,
0458: final String searchedFullyQualifiedClassName,
0459: final Vector classReferences,
0460: final boolean doTrackAttributes) {
0461:
0462: //ystem.out.println("cc> scanForClassUsage for " +
0463: // candidateFSD.fullyQualifiedClassNameBuffer.toString() +
0464: // " starts." );
0465:
0466: // This here really is very easy:
0467: // Just deepscan for ClassOrInterfaceType nodes and compare
0468: // the contained identifier leaf. This will catch all
0469: // occurences in method parameters, typecasts, attribute assignments..
0470:
0471: // A work vector for the loop:
0472: Vector workTargetVector = new Vector();
0473:
0474: // The basisNode = CompilationUnit isn't interesting, so get its children :
0475: final DefaultMutableTreeNode[] basisNodeChildren = this
0476: .getChildren(javaCCBasisNode);
0477: for (int basisNodeIndex = 0; basisNodeIndex < basisNodeChildren.length; basisNodeIndex++) {
0478: // Nodes have String user objects:
0479: final DefaultMutableTreeNode this Child = basisNodeChildren[basisNodeIndex];
0480: final Object userObject = this Child.getUserObject();
0481: if (userObject instanceof Integer) {
0482: // Integer reference comparison is ok here.
0483: if ((Integer) userObject == ParserOutputProcessor.NodeForTypeDeclaration) {
0484: // Get the ClassDeclaration children:
0485: DefaultMutableTreeNode[] classDeclarationNodes = this
0486: .getAllChildNodesWithName(
0487: this Child,
0488: ParserOutputProcessor.NodeForClassOrInterfaceDeclaration);
0489: for (int classDecIndex = 0; classDecIndex < classDeclarationNodes.length; classDecIndex++) {
0490: // Get the ClassBody node children:
0491: DefaultMutableTreeNode[] classBodyNodes = this
0492: .getAllChildNodesWithName(
0493: classDeclarationNodes[classDecIndex],
0494: ParserOutputProcessor.NodeForClassOrInterfaceBody);
0495: for (int classBodyIndex = 0; classBodyIndex < classBodyNodes.length; classBodyIndex++) {
0496: // Get the ClassBodyDeclaration node children:
0497: DefaultMutableTreeNode[] classBodyDeclarationNodes = this
0498: .getAllChildNodesWithName(
0499: classBodyNodes[classBodyIndex],
0500: ParserOutputProcessor.NodeForClassOrInterfaceBodyDeclaration);
0501: for (int classBodyDeclarationIndex = 0; classBodyDeclarationIndex < classBodyDeclarationNodes.length; classBodyDeclarationIndex++) {
0502: // The children of the classBodyDeclarationNodes are
0503: // FieldDeclaration, ConstructorDeclaration or MethodDeclaration nodes.
0504: final DefaultMutableTreeNode cbdNode = classBodyDeclarationNodes[classBodyDeclarationIndex];
0505: this
0506: .deepScanForClassIdentifierOccurences(
0507: candidateFSD,
0508: classReferences,
0509: cbdNode,
0510: searchedFullyQualifiedClassName,
0511: workTargetVector);
0512: }
0513: }
0514: } // for classDecIndex
0515: } // if
0516: } // if
0517: } // for basisNodeIndex
0518:
0519: // Optionally track all ( member and local ) attributes of this class.
0520: // This again is simple: Just use the member and localblock attribute vectors
0521: // of the candidate fsd, which has been processed with localfields for this
0522: // purpose before:
0523: if (doTrackAttributes) {
0524: // Track attributes of the cadidateFSD and
0525: // recur over all nested and anonymous classes.
0526: // For this initial call, candidateFSD also is the toplevel fsd,
0527: // therefore it occurs twice. When the called method calls itself
0528: // during recursion, this won't be the case anymore.
0529: this .addAttributesForClassSearchForFSD(candidateFSD,
0530: javaCCBasisNode, candidateFSD,
0531: searchedFullyQualifiedClassName, classReferences);
0532: } // if doTrackAttributes
0533:
0534: //ystem.out.println("cc> scanForClassUsage for " +
0535: // candidateFSD.fullyQualifiedClassNameBuffer.toString() +
0536: // " has ended." );
0537:
0538: } // scanForClassUsageOf
0539:
0540: /**
0541: * Recursive method: Adds attributes for classsearches over this
0542: * fsd and recurs over nested and anonymous classes:
0543: */
0544: private void addAttributesForClassSearchForFSD(
0545: final FileStructureDescription topLevelFSD,
0546: final DefaultMutableTreeNode topLevelJavaCCBasisNode,
0547: final FileStructureDescription candidateFSD,
0548: final String searchedFullyQualifiedClassName,
0549: final Vector classReferences) {
0550: String globalScopeType = (topLevelFSD == candidateFSD) ? "toplevel"
0551: : "nested";
0552: // Process the passed fsd:
0553: this .addAttributesForClassSearch(topLevelFSD,
0554: topLevelJavaCCBasisNode,
0555: candidateFSD.fieldDescriptions, globalScopeType
0556: + " member", searchedFullyQualifiedClassName,
0557: classReferences);
0558: this .addAttributesForClassSearch(topLevelFSD,
0559: topLevelJavaCCBasisNode,
0560: candidateFSD.localBlockFieldDescriptions,
0561: globalScopeType + " local",
0562: searchedFullyQualifiedClassName, classReferences);
0563: // and recur over
0564: // 1) nested fsd's of the passed candidateFSD :
0565: for (int i = 0; i < candidateFSD.innerClasses.size(); i++) {
0566: final FileStructureDescription innerClassFSD = (FileStructureDescription) candidateFSD.innerClasses
0567: .elementAt(i);
0568: this .addAttributesForClassSearchForFSD(topLevelFSD,
0569: topLevelJavaCCBasisNode, innerClassFSD,
0570: searchedFullyQualifiedClassName, classReferences);
0571: } // for
0572: // 2. anonymous fsd's of the passed candidateFSD :
0573: for (int i = 0; i < candidateFSD.localBlockAnonymousClasses
0574: .size(); i++) {
0575: final FileStructureDescription anonymousClassFSD = (FileStructureDescription) candidateFSD.localBlockAnonymousClasses
0576: .elementAt(i);
0577: this .addAttributesForClassSearchForFSD(topLevelFSD,
0578: topLevelJavaCCBasisNode, anonymousClassFSD,
0579: searchedFullyQualifiedClassName, classReferences);
0580: } // for
0581: } // addAttributesForClassSearch
0582:
0583: private void addAttributesForClassSearch(
0584: final FileStructureDescription topLevelFSD,
0585: final DefaultMutableTreeNode topLevelJavaCCBasisNode,
0586: final Vector fields, // members or local ones
0587: final String scopeType, // associated text for inserting
0588: final String searchedFullyQualifiedClassName,
0589: final Vector classReferences) {
0590: // work vector reference for the attribute searches:
0591: Vector attributeSearchReferences = new Vector();
0592: // The topLevelFSD is used for combining class identifiers
0593: // with importstatements.
0594: for (int i = 0; i < fields.size(); i++) {
0595: final FileStructureDescriptionForField fieldFSD = (FileStructureDescriptionForField) fields
0596: .elementAt(i);
0597: if (!fieldFSD.isPrimitiveType) {
0598: final String localQualifier = fieldFSD
0599: .getFullyQualifiedClassName(false);
0600: final String[] inScopePossibleIdentifiers = CodeCompletionUtilities
0601: .CreatePossibleQualifiedClassIdentifiers(
0602: topLevelFSD, localQualifier.toString());
0603: boolean found = false;
0604: for (int p = 0; p < inScopePossibleIdentifiers.length; p++) {
0605: if (inScopePossibleIdentifiers[p]
0606: .equals(searchedFullyQualifiedClassName)) {
0607: found = true;
0608: break;
0609: }
0610: }
0611: if (found) {
0612: // Make an attribute search for this field and pass the line, where
0613: // this attribute is defined, so one always is inscope:
0614: attributeSearchReferences.setSize(0);
0615: // Caution: We already are in a ThreadEngine Thread Context,
0616: // and we ONLY want the attribute search inside the
0617: // topLevelFSD, therefore use scanForFieldCallsOf():
0618: this .scanForFieldCallsOf(topLevelFSD,
0619: topLevelJavaCCBasisNode,
0620: fieldFSD.objectNameWithPosition.content,
0621: attributeSearchReferences);
0622:
0623: // Convert the found FieldReferenceEntry elements into
0624: // ClassReferenceEntry elements for this class search :
0625: for (int k = 0; k < attributeSearchReferences
0626: .size(); k++) {
0627: final FieldReferenceEntry fieldRef = (FieldReferenceEntry) attributeSearchReferences
0628: .elementAt(k);
0629: final ClassReferenceEntry entry = new ClassReferenceEntry(
0630: topLevelFSD, scopeType + " "
0631: + fieldRef.getFieldName(),
0632: fieldRef.getStartLine(), fieldRef
0633: .getStartColumn(), fieldRef
0634: .getEndLine(), fieldRef
0635: .getEndColumn());
0636: classReferences.addElement(entry);
0637: } // for k
0638: attributeSearchReferences.setSize(0);
0639: }
0640: } // if
0641: } // for
0642: } // addAttributesForClassSearch
0643:
0644: private void deepScanForClassIdentifierOccurences(
0645: final FileStructureDescription candidateFSD,
0646: final Vector classReferences,
0647: final DefaultMutableTreeNode cbdNode,
0648: final String searchedFullyQualifiedClassName,
0649: final Vector workTargetVector) {
0650: // 1 of 2: Search the identifier leafs of all ClassOrInterfaceType nodes:
0651: // This gets all declarations and casts.
0652: //
0653: // Reset the work vector and fill it with all found ClassOrInterfaceType nodes:
0654: workTargetVector.setSize(0);
0655: this
0656: .deepScanForNodesWithName(
0657: workTargetVector,
0658: cbdNode,
0659: ParserOutputProcessor.NodeForClassOrInterfaceType,
0660: true);
0661: DefaultMutableTreeNode workNode;
0662: String localQualifier;
0663: for (int i = 0; i < workTargetVector.size(); i++) {
0664: // Get the identifier leaf content from this ClassOrInterfaceType node:
0665: // Search and return the leaf with kind = <IDENTIFIER> : ( = class identifier )
0666: workNode = (DefaultMutableTreeNode) workTargetVector
0667: .elementAt(i);
0668: final TokenTreeUserObject classNameLeaf = this
0669: .getChildLeafOfKind(workNode, "<IDENTIFIER>");
0670: if (classNameLeaf != null) {
0671: localQualifier = classNameLeaf.getContent();
0672: // However the identifiers found in the javacc tree can be non qualified
0673: // or partially qualified, so one must compare against all combinations
0674: // of possible import wildcards and also take complete import statements
0675: // without wildcards into account:
0676: final String[] inScopePossibleIdentifiers = CodeCompletionUtilities
0677: .CreatePossibleQualifiedClassIdentifiers(
0678: candidateFSD, localQualifier);
0679: boolean found = false;
0680: for (int p = 0; p < inScopePossibleIdentifiers.length; p++) {
0681: if (inScopePossibleIdentifiers[p]
0682: .equals(searchedFullyQualifiedClassName)) {
0683: found = true;
0684: break;
0685: }
0686: }
0687: if (found) {
0688: ClassReferenceEntry entry = new ClassReferenceEntry(
0689: candidateFSD, new String(localQualifier),
0690: classNameLeaf.getStartLine(), classNameLeaf
0691: .getStartColumn(), classNameLeaf
0692: .getEndLine(), classNameLeaf
0693: .getEndColumn());
0694: classReferences.addElement(entry);
0695: }
0696: } // if
0697: } // for
0698: workTargetVector.setSize(0);
0699: //
0700: // 2 of 2 :
0701: // Search occurences of the searchedFullyQualifiedClassName in
0702: // name node leaf identifiers.
0703: // For this purpose, one needs the first identifier leaf content of the name
0704: // node and the concatenation of all following leafs of the name node.
0705: // The first identifier is combined with all possible import statements
0706: // and the concatenation of the following leafs is appended.
0707: // If one of these starts with the searchedFullyQualifiedClassName,
0708: // one has found a match [f.ex. a call of a public static method inside a method block]
0709: workTargetVector.setSize(0);
0710: this .deepScanForNodesWithName(workTargetVector, cbdNode,
0711: ParserOutputProcessor.NodeForName, true);
0712: for (int i = 0; i < workTargetVector.size(); i++) {
0713: workNode = (DefaultMutableTreeNode) workTargetVector
0714: .elementAt(i);
0715: // Take the first identifier:
0716: final TokenTreeUserObject firstIdentifierLeaf = this
0717: .getChildLeafOfKind(workNode, "<IDENTIFIER>");
0718: // and the concatenation of all:
0719: final StringWithPosition completeLine = this
0720: .concatenateLeafContentsOf(workNode);
0721:
0722: if ((firstIdentifierLeaf != null) && (completeLine != null)) {
0723: boolean found = false;
0724: // If the completeLine starts with the searchedFullyQualifiedClassName
0725: // we have a match. The identifier is adressed absolutely in this case:
0726: if (completeLine.content
0727: .startsWith(searchedFullyQualifiedClassName)) {
0728: found = true;
0729: } else {
0730: String firstIdentifier = firstIdentifierLeaf
0731: .getContent();
0732: // Combine this one with all import statement combinations:
0733: final String[] inScopePossibleIdentifiers = CodeCompletionUtilities
0734: .CreatePossibleQualifiedClassIdentifiers(
0735: candidateFSD, firstIdentifier);
0736: for (int p = 0; p < inScopePossibleIdentifiers.length; p++) {
0737: if (inScopePossibleIdentifiers[p]
0738: .equals(searchedFullyQualifiedClassName)) {
0739: found = true;
0740: break;
0741: }
0742: }
0743: } // else
0744: if (found) {
0745: ClassReferenceEntry entry = new ClassReferenceEntry(
0746: candidateFSD, new String(
0747: firstIdentifierLeaf.getContent()),
0748: firstIdentifierLeaf.getStartLine(),
0749: firstIdentifierLeaf.getStartColumn(),
0750: firstIdentifierLeaf.getEndLine(),
0751: firstIdentifierLeaf.getEndColumn());
0752: classReferences.addElement(entry);
0753: }
0754: } // if
0755: } // for
0756: workTargetVector.setSize(0);
0757: } // deepScanForClassIdentifierOccurences
0758:
0759: /**
0760: * Returns the (first) leaf of the passed kind.
0761: */
0762: private TokenTreeUserObject getChildLeafOfKind(
0763: final DefaultMutableTreeNode parentNode,
0764: final String leafKind) {
0765: final DefaultMutableTreeNode[] allChildren = this
0766: .getChildren(parentNode);
0767: TokenTreeUserObject foundLeaf = null;
0768: for (int i = 0; i < allChildren.length; i++) {
0769: final DefaultMutableTreeNode this Child = allChildren[i];
0770: if (this Child.getUserObject() instanceof TokenTreeUserObject) {
0771: final TokenTreeUserObject this UserObject = (TokenTreeUserObject) this Child
0772: .getUserObject();
0773: if (this UserObject.getKind().equals(leafKind)) {
0774: foundLeaf = this UserObject;
0775: break;
0776: }
0777: }
0778: }
0779: return foundLeaf;
0780: }
0781:
0782: /**
0783: * Takes all children of the passed node, and concatenates
0784: * all contents of the ones which are leafs to the content
0785: * of a StringWithPosition object.
0786: * Positioning numbers also are set.
0787: */
0788: private StringWithPosition concatenateLeafContentsOf(
0789: final DefaultMutableTreeNode node) {
0790: final DefaultMutableTreeNode[] children = this
0791: .getChildren(node);
0792: final StringBuffer contents = new StringBuffer();
0793: int startLine = -1;
0794: int startColumn = -1;
0795: int endLine = -1;
0796: int endColumn = -1;
0797: for (int i = 0; i < children.length; i++) {
0798: if (children[i].getUserObject() instanceof TokenTreeUserObject) {
0799: final TokenTreeUserObject tokenContent = (TokenTreeUserObject) children[i]
0800: .getUserObject();
0801: contents.append(tokenContent.getContent());
0802: if (startLine == -1) // it hasn't been set yet
0803: {
0804: startLine = tokenContent.getStartLine();
0805: startColumn = tokenContent.getStartColumn();
0806: } else // start has been set, so extend the other side
0807: {
0808: endLine = tokenContent.getEndLine();
0809: endColumn = tokenContent.getEndColumn();
0810: }
0811: }
0812: } // for
0813: return new StringWithPosition(contents.toString(), startLine,
0814: startColumn, endLine, endColumn);
0815: } // concatenateLeafContentsOf
0816:
0817: /**
0818: * Search all locations everywhere (= in the src, additional libs and the whole project),
0819: * where the method given by the passed methodFSD inside the methodParentFSD inside the
0820: * topLevelSourceFileFSD is called.
0821: *
0822: * The methodParentTree in all cases is the fsd which contains the methodfsd.
0823: *
0824: * If the method is toplevel, methodParentFSD equals topLevelSourceFileFSD.
0825: *
0826: * topLevelSourceFileFSD = the fsd, containing the passed methodfsd directly or
0827: * somewhere in its innerclasses or innerinterfaces tree, and:
0828: * topLevelSourceFileFSD is 1:1 related to the associated sourcefile.
0829: *
0830: */
0831: public void searchMethodUsageLocationsFor(
0832: final SearchMethodFSDResult methodFSDResult,
0833: final FileStructureDescription[] selectedTargetFSDs) {
0834: // Wait until the other popups have goone, so the
0835: // way is cleared for a new progresswindow:
0836: EventQueue.invokeLater(new Runnable() {
0837: public void run() {
0838: // We must call the dependencies updater and tell it to process all
0839: // pending entries. For this and other reasons, we must process this
0840: // in a user thread, otherwise one could produce deadlocks:
0841: Runnable searchRunnable = new Runnable() {
0842: public void run() {
0843: // Give Swing some time right now (to show the progressWindow):
0844: //try{ Thread.sleep(1199); } catch( Exception e2 ){}
0845: searchMethodUsageLocations_InThread(
0846: methodFSDResult, selectedTargetFSDs);
0847: }
0848: };
0849: ThreadEngine.getInstance().addRunnable(searchRunnable,
0850: "searchMethodUsageLocationsFor");
0851: }
0852: });
0853: } // searchMethodUsageLocationsFor
0854:
0855: /**
0856: * Carried out in a user thread, called by searchMethodUsageLocationsFor() above.
0857: */
0858: private void searchMethodUsageLocations_InThread(
0859: final SearchMethodFSDResult methodFSDResult,
0860: final FileStructureDescription[] selectedTargetFSDs) {
0861: searchHasBeenCancelledByTheUser = false; // initialize
0862: String searchName = "Method"; // is displayed as tab title in the search results panel
0863: // Make sure, the searchresults tree displays some useful information
0864: // while the search is running, and reset it, if the search didn't find anything.
0865: this .projectFrame.initializeSearchResults(searchName,
0866: searchMessage);
0867: // Give Swing some time right now:
0868: try {
0869: Thread.sleep(44);
0870: } catch (Exception e0) {
0871: }
0872: // Call the actual worker method:
0873: boolean elementsHaveBeenFound = this
0874: .search_Method_Usage_Locations_In_Thread(searchName,
0875: methodFSDResult, selectedTargetFSDs);
0876: if (!elementsHaveBeenFound) {
0877: // Signalize it's ready for new searches:
0878: this .projectFrame.initializeSearchResults(searchName,
0879: Language.Translate("No hits"));
0880: // Give Swing some time right now:
0881: try {
0882: Thread.sleep(44);
0883: } catch (Exception e2) {
0884: }
0885: }
0886: } // searchMethodUsageLocations_InThread
0887:
0888: private boolean search_Method_Usage_Locations_In_Thread(
0889: final String searchName,
0890: final SearchMethodFSDResult methodFSDResult,
0891: final FileStructureDescription[] selectedTargetFSDs) {
0892: boolean elementsHaveBeenFound = false;
0893: long startTime = System.currentTimeMillis();
0894: String methodName = methodFSDResult.fsd.name.content;
0895: // Make the progressWindow and show it, if the search
0896: // has package or global scope, otherwise the search is so fast,
0897: // that the progressWindow is not needed:
0898: ProgressWindow progressWindowCandidate = null;
0899: if (!methodFSDResult.fsd.isPrivate()) {
0900: String windowText = searchMessage + "\n"
0901: + searchInfoMessage;
0902: progressWindowCandidate = new ProgressWindow(windowText,
0903: null, projectFrame.getParentFrameForChildren(),
0904: projectFrame.getMainFrameProvider(), true);
0905: progressWindowCandidate.showCentered();
0906: }
0907: final ProgressWindow progressWindow = progressWindowCandidate;
0908:
0909: FileStructureDescriptionManager fsdManager = this .projectFrame
0910: .getFileStructureDescriptionManager();
0911: // We need the file dependencies list to be complete, so tell the
0912: // dependencies updater to process all pending entries right now.
0913: // The pc must be in a user thread context for this.
0914: fsdManager.waitForUpdaters();
0915:
0916: // Make the set of possible files to be searched smaller by useing
0917: // the visibility of the method. If parentfsd's and interfaces are selected to,
0918: // we still can use the leaf method visibility for all, because it's the
0919: // biggest visibility.
0920: Vector dependentFSDs = new Vector();
0921: if (methodFSDResult.fsd.isPrivate()) {
0922: // The method is private, so we only have to search in
0923: // the basis FSD, which contains that method.
0924: // Nothing to do with the selectedTargetFSDs here (These contain
0925: // the methodFSDResult.basisFSD, possibly as the only element)
0926: dependentFSDs.addElement(methodFSDResult.basisFSD);
0927: } else if (methodFSDResult.fsd.isPackageScope()) {
0928: // First add all files, which depend from the basisFSD
0929: // and any project class and its dependent classes in the parent chain:
0930: for (int k = 0; k < selectedTargetFSDs.length; k++) {
0931: this .addAllFSDsWhichDependFrom(selectedTargetFSDs[k],
0932: dependentFSDs, fsdManager);
0933: } // for k
0934: // but then exclude all, which are not in the same package:
0935: int exIndex = 0;
0936: FileStructureDescription workFSD = null;
0937: final String basisPackageName = methodFSDResult.basisFSD.packageName.content;
0938: if (basisPackageName.length() > 0) {
0939: while (exIndex < dependentFSDs.size()) {
0940: workFSD = (FileStructureDescription) dependentFSDs
0941: .elementAt(exIndex);
0942: if (workFSD.packageName.content
0943: .startsWith(basisPackageName)) {
0944: exIndex++; // ok proceed
0945: } else {
0946: dependentFSDs.removeElementAt(exIndex); // remove it
0947: }
0948: } // while
0949: } // if
0950: } else {
0951: // Add all files, which depend from the basisFSD
0952: // and any project class and its dependent classes in the parent chain:
0953: for (int k = 0; k < selectedTargetFSDs.length; k++) {
0954: this .addAllFSDsWhichDependFrom(selectedTargetFSDs[k],
0955: dependentFSDs, fsdManager);
0956: }
0957: } //else
0958: //
0959: // Jedes File in der obigen Liste muss auf Block parsernode level durchsucht werden
0960: // nach relativen oder absoluten Referenzen der Basisklasse und dann nach
0961: // expliziten Methodenaufrufen der obigen Zielmethode.
0962: //
0963: // Zunächst lasse ich die Vererbung beiseite und beruecksichtige nur
0964: // Toplevel-Instanzen mit dynamischen oder statischen Methoden
0965: // also folgende zwei Formen:
0966: // instance.dynamicMethod( ... ) oder Class.StaticMethod( ... )
0967: //
0968: // instance oder Class konnen relativ oder qualifiziert sein.
0969: //
0970: // instance kann Member Attribut oder lokale Variable sein.
0971: //
0972: // Zusätzlich sind auch "verdeckte" Calls möglich:
0973: //
0974: // anotherClassInstance.getMyInstance().dynamicMethod().sayHello()
0975: //
0976: //
0977: FileStructureDescriptionParserTreePostProcessor postProcessor = new FileStructureDescriptionParserTreePostProcessor(
0978: fsdManager);
0979: // Fill all hits into ClassReferenceEntry objects and add them to this vector:
0980: Vector classReferences = new Vector();
0981: if (progressWindow != null) {
0982: progressWindow.setProgressMaxValue(dependentFSDs.size());
0983: }
0984: for (int fsdIndex = 0; fsdIndex < dependentFSDs.size(); fsdIndex++) {
0985: if (progressWindow != null) {
0986: final int progressValue = fsdIndex;
0987: EventQueue.invokeLater(new Runnable() {
0988: public void run() {
0989: progressWindow.setProgressValue(progressValue);
0990: }
0991: });
0992: // Break the search, if the user has pushed the cancel button:
0993: if (progressWindow.getWasCancelled()) {
0994: searchHasBeenCancelledByTheUser = true;
0995: break;
0996: }
0997: try {
0998: Thread.yield();
0999: } catch (Exception e234986) {
1000: }
1001: }
1002: final FileStructureDescription candidateFSD = (FileStructureDescription) dependentFSDs
1003: .elementAt(fsdIndex);
1004: // Get the associated source text (can be from java files or from jar archives)
1005: final StringBuffer candidateSourceCode = fsdManager
1006: .getJavaSourceForFSD(candidateFSD);
1007: // Get the full parser tree:
1008: final ParserTreeNode compilationUnitNode = this
1009: .getCompilationUnitNodeFor(candidateSourceCode,
1010: candidateFSD.fullyQualifiedClassNameBuffer
1011: .toString());
1012: // For the following scan, the fsd must have the local fields, which usually only
1013: // are parsed for fsd's of sources, which are going to be displayed in the source editor.
1014: // This actions here are made for many fsd's, which of course are not displayed in
1015: // the editor, so we have to update them to have the local fields information:
1016: // Note the two flags:
1017: // create local fields = true ( as mentionned above )
1018: // call dependency scanner = true : Because the dependency fields are cleared
1019: // by the postProcessor, the dependencies
1020: // ALWAYS must be recalculated.
1021: // Because the postprocessor stores
1022: // the compilationrootnode and the fsd in the entries
1023: // sent to the dependency updater, this doesn't
1024: // cost much time:
1025: // This all is done on the same fsd reference.
1026: postProcessor.updatePostProcessParserTree(candidateFSD,
1027: candidateFSD.belongsToProject, compilationUnitNode,
1028: candidateFSD.pathNameBuffer.toString(), true, /* create local fields */
1029: true /* call dependency scanner */);
1030: // Now deepscan the tree for occurences of calls of the searched method:
1031: // For any found location (defined by the line and column numbers) we do the same
1032: // like done, when the declaration of the method is searched and see, if we
1033: // land in the targetFSD or not. If we do land in the targetFSD, a call location
1034: // has been found.
1035: this .scanForMethodCallsOf(candidateFSD,
1036: compilationUnitNode, methodName, classReferences);
1037: } // for
1038:
1039: if (!this .searchHasBeenCancelledByTheUser) {
1040: // Not absolutely required, but more secure, because at least the queue of the
1041: // dependency updater will contain some entries: Force to perform all pending
1042: // entries again:
1043: fsdManager.waitForUpdaters();
1044: // If the "jump to declaration" procedure returns the methodFSDResult.basisFSD,
1045: // one can add a jump-to-method-call action to the searchresults tree:
1046: Vector searchResultsUserObjectVector = new Vector();
1047: for (int i = 0; i < classReferences.size(); i++) {
1048: final MethodReferenceEntry entry = (MethodReferenceEntry) classReferences
1049: .elementAt(i);
1050: // We need the SourceEditorDocument:
1051: EditableLeafObject leaf = fsdManager
1052: .getJavaSourceEditorLeafForFSD(entry
1053: .getClassDescription());
1054: // On leaf level, one should unload the content, after having loaded and processed it.
1055: // But one shouldn't unload it, if it already was loaded by another one, when this method starts.
1056: // It's not serious, if this doesn't work some times, so no need for synchronization here.
1057: boolean leafWasLoadedInitially = leaf.isContentLoaded();
1058: Object leafContent = leaf.getContent();
1059: if (leafContent instanceof SourceEditorDocument) {
1060: final SourceEditorDocument sourceDoc = (SourceEditorDocument) leafContent;
1061: if (this .getIsMethodDeclarationLocatedIn(sourceDoc,
1062: entry, methodFSDResult, selectedTargetFSDs,
1063: fsdManager)) {
1064: // Create a SearchResultsFileNodeUserObject and add it to the vector:
1065: final int docPosition = sourceDoc
1066: .getPositionOfStartOfLine(entry
1067: .getStartLine() - 1)
1068: + (entry.getStartColumn() + entry
1069: .getEndColumn()) / 2;
1070: final boolean breakAtPoints = false;
1071: final int[] nearestWordPosition = sourceDoc
1072: .getNearestWordPositionTo(docPosition,
1073: breakAtPoints);
1074: final int startOffset = nearestWordPosition[0];
1075: final int endOffset = nearestWordPosition[1];
1076:
1077: final SearchResultsUserObject resultUserObject = new SearchResultsUserObject(
1078: leaf, entry.getStartLine() - 1,
1079: docPosition, entry.getEndColumn()
1080: - entry.getStartColumn() + 1);
1081:
1082: searchResultsUserObjectVector
1083: .addElement(resultUserObject);
1084: } // if
1085: else {
1086: Log
1087: .Info("getIsMethodDeclarationLocatedIn returned false for "
1088: + entry.getClassDescription().fullyQualifiedClassNameBuffer
1089: .toString());
1090: }
1091: } // if
1092: else {
1093: Log
1094: .Error("leafContent as NOT instanceof SourceEditorDocument");
1095: }
1096: // Be careful with unloading: One only is allowed to unload the leaf,
1097: // if it has not been loaded, when this method has started, otherwise we could
1098: // possibly unload a leaf, which currently is displayed in the editor, which
1099: // would cause the editor to crash soon after this.
1100: if (!leafWasLoadedInitially) {
1101: leaf.unloadContent(false); // make memory of this available sooner (gc)
1102: }
1103: } // for
1104:
1105: /*
1106: long elapsedTime = System.currentTimeMillis() - startTime;
1107: Log.Info("elapsedTime= " + elapsedTime );
1108: Log.Info("Found " + searchResultsUserObjectVector.size() + " hits.");
1109: */
1110:
1111: // Close and dipose the progressWindow, if it has been created:
1112: if (progressWindow != null) {
1113: EventQueue.invokeLater(new Runnable() {
1114: public void run() {
1115: progressWindow.setVisible(false);
1116: progressWindow.dispose();
1117: }
1118: });
1119: // Give Swing some time right now:
1120: try {
1121: Thread.sleep(88);
1122: } catch (Exception e1) {
1123: }
1124: } // if
1125:
1126: // Tell the searchresults tree to display action-entries for the
1127: // found results, if some were found:
1128: if (searchResultsUserObjectVector.size() > 0) {
1129: elementsHaveBeenFound = true;
1130: SearchResultsUserObject[] searchResultsUserObjects = new SearchResultsUserObject[searchResultsUserObjectVector
1131: .size()];
1132: searchResultsUserObjectVector
1133: .copyInto(searchResultsUserObjects);
1134: this .projectFrame
1135: .setSearchResultsTreeContentWithObjectSearchResults(
1136: searchName, searchResultsUserObjects);
1137: } else {
1138: String title = Language
1139: .Translate("Object Search Results");
1140: String message = Language
1141: .Translate("The object search hasn't found any results.");
1142: JOptionPane
1143: .showMessageDialog(this .projectFrame, message,
1144: title, JOptionPane.INFORMATION_MESSAGE);
1145: }
1146: classReferences.setSize(0); // GC assistance
1147: }
1148: return elementsHaveBeenFound;
1149: } // searchMethodUsageLocations_InThread
1150:
1151: /**
1152: * Like searchMethodUsageLocationsFor(), see explanations there.
1153: * This one operates on attributes.
1154: * The currentFSD and currentLineNumber are required for resolving
1155: * LOCAL attribute by scope comparison.
1156: */
1157: public void searchFieldUsageLocationsFor(
1158: final SearchFieldFSDResult fieldFSDResult,
1159: final FileStructureDescription[] selectedTargetFSDs,
1160: final FileStructureDescription currentFSD,
1161: final int currentLineNumber) {
1162: // Note: We call the java parser below, which will clear some fields.
1163: // Especially the field fsd in fieldFSDResult will not survive this and will
1164: // have some null attributes after this.
1165: // Therefore we must clone this here:
1166: fieldFSDResult.fsd = fieldFSDResult.fsd.cloneInstance();
1167:
1168: //ystem.out.println("SymbolUsageLocationSearch:searchFieldUsageLocationsFor() starts...");
1169:
1170: final String searchName = "Field"; // is displayed as tab title in the search results panel
1171:
1172: // Wait until the other popups have goone, so the
1173: // way is cleared for a new progresswindow:
1174: EventQueue.invokeLater(new Runnable() {
1175: public void run() {
1176: // We must call the dependencies updater and tell it to process all
1177: // pending entries. For this and other reasons, we must process this
1178: // in a user thread, otherwise one could produce deadlocks:
1179: Runnable searchRunnable = new Runnable() {
1180: public void run() {
1181: // Give Swing some time right now (to show the progressWindow):
1182: //try{ Thread.sleep(1199); } catch( Exception e2 ){}
1183: searchFieldUsageLocations_InThread(searchName,
1184: fieldFSDResult, selectedTargetFSDs,
1185: currentFSD, currentLineNumber);
1186: }
1187: };
1188: ThreadEngine.getInstance().addRunnable(searchRunnable,
1189: "searchFieldUsageLocationsFor");
1190: }
1191: });
1192: } // searchFieldUsageLocationsFor
1193:
1194: /**
1195: * Carried out in a user thread, called by searchFieldUsageLocationsFor() above.
1196: */
1197: private void searchFieldUsageLocations_InThread(
1198: final String searchName,
1199: final SearchFieldFSDResult fieldFSDResult,
1200: final FileStructureDescription[] selectedTargetFSDs,
1201: final FileStructureDescription currentFSD,
1202: final int currentLineNumber) {
1203: searchHasBeenCancelledByTheUser = false; // initialize
1204: // Make sure, the searchresults tree displays some useful information
1205: // while the search is running, and reset it, if the search didn't find anything.
1206: this .projectFrame.initializeSearchResults(searchName,
1207: searchMessage);
1208: // Give Swing some time right now:
1209: try {
1210: Thread.sleep(44);
1211: } catch (Exception e0) {
1212: }
1213: // Call the actual worker method:
1214: boolean elementsHaveBeenFound = this
1215: .search_Field_Usage_Locations_In_Thread(searchName,
1216: fieldFSDResult, selectedTargetFSDs, currentFSD,
1217: currentLineNumber);
1218: if (!elementsHaveBeenFound) {
1219: // Signalize it's ready for new searches:
1220: this .projectFrame.initializeSearchResults(searchName,
1221: Language.Translate("No hits"));
1222: // Give Swing some time right now:
1223: try {
1224: Thread.sleep(44);
1225: } catch (Exception e2) {
1226: }
1227: }
1228: } // searchFieldUsageLocations_InThread
1229:
1230: private boolean search_Field_Usage_Locations_In_Thread(
1231: final String searchName,
1232: SearchFieldFSDResult fieldFSDResult,
1233: final FileStructureDescription[] selectedTargetFSDs,
1234: final FileStructureDescription currentFSD,
1235: final int currentLineNumber) {
1236: /* Debug:
1237: Log.Info("qqqq33> AttributeUsageLocationDialog: search_Field_Usage_Locations_In_Thread");
1238: SearchFieldFSDResult theFieldFSDResult = fieldFSDResult;
1239: FileStructureDescriptionForField fieldFSD = theFieldFSDResult.fsd;
1240: Log.Info("qqqq33> fieldFSD.simpleClassName.content " +
1241: fieldFSD.simpleClassName.content );
1242: Log.Info("qqqq33> fieldFSD.objectNameWithPosition.content " +
1243: fieldFSD.objectNameWithPosition.content );
1244: */
1245:
1246: boolean elementsHaveBeenFound = false;
1247: long startTime = System.currentTimeMillis();
1248: String fieldName = fieldFSDResult.fsd.objectNameWithPosition.content;
1249: // Make the progressWindow and show it, if the search
1250: // has package or global scope, otherwise the search is so fast,
1251: // that the progressWindow is not needed:
1252: ProgressWindow progressWindowCandidate = null;
1253: if (!fieldFSDResult.fsd.isPrivate()) {
1254: String windowText = searchMessage + "\n"
1255: + searchInfoMessage;
1256: progressWindowCandidate = new ProgressWindow(windowText,
1257: null, projectFrame.getParentFrameForChildren(),
1258: projectFrame.getMainFrameProvider(), true);
1259: progressWindowCandidate.showCentered();
1260: }
1261: final ProgressWindow progressWindow = progressWindowCandidate;
1262:
1263: FileStructureDescriptionManager fsdManager = this .projectFrame
1264: .getFileStructureDescriptionManager();
1265: // We need the file dependencies list to be complete, so tell the
1266: // dependencies updater to process all pending entries right now.
1267: // The pc must be in a user thread context for this.
1268: fsdManager.waitForUpdaters();
1269:
1270: //ystem.out.println(">fs111> SymbolUsageLocationSearch: Search field for " +
1271: // fieldFSDResult.fsd.objectNameWithPosition.content );
1272:
1273: // Make the set of possible files to be searched smaller by useing
1274: // the visibility of the field. If parentfsd's and interfaces are selected to,
1275: // we still can use the leaf method visibility for all, because it's the
1276: // biggest visibility.
1277: Vector dependentFSDs = new Vector();
1278: // Additional case for attributes: For member attributes, the scopeStartLine
1279: // and scopeEndLine of the field fsd is set both to zero.
1280: // IF these two parameters are not zero, the attribute isn't a member attribute,
1281: // but is a LOCAL attribute with scope given by these two values.
1282: if ((fieldFSDResult.fsd.scopeStartLine > 0)
1283: && (fieldFSDResult.fsd.scopeEndLine > 0)) {
1284:
1285: //ystem.out.println(">fs> is local");
1286:
1287: // In this case, the attribute is LOCAL, so we only have to search in
1288: // the basis FSD, which contains that method.
1289: // Nothing to do with the selectedTargetFSDs here (These contain
1290: // the methodFSDResult.basisFSD, possibly as the only element)
1291: dependentFSDs.addElement(fieldFSDResult.basisFSD);
1292: } else if (fieldFSDResult.fsd.isPrivate()) {
1293:
1294: //ystem.out.println(">fs> is private");
1295:
1296: // The method is private, so we only have to search in
1297: // the basis FSD, which contains that method.
1298: // Nothing to do with the selectedTargetFSDs here (These contain
1299: // the methodFSDResult.basisFSD, possibly as the only element)
1300: dependentFSDs.addElement(fieldFSDResult.basisFSD);
1301: } else if (fieldFSDResult.fsd.isPackageScope()) {
1302:
1303: //ystem.out.println(">fs> has package scope");
1304:
1305: // First add all files, which depend from the basisFSD
1306: // and any project class and its dependent classes in the parent chain:
1307: for (int k = 0; k < selectedTargetFSDs.length; k++) {
1308: this .addAllFSDsWhichDependFrom(selectedTargetFSDs[k],
1309: dependentFSDs, fsdManager);
1310: } // for k
1311: // but then exclude all, which are not in the same package:
1312: int exIndex = 0;
1313: FileStructureDescription workFSD = null;
1314: final String basisPackageName = fieldFSDResult.basisFSD.packageName.content;
1315: if (basisPackageName.length() > 0) {
1316: while (exIndex < dependentFSDs.size()) {
1317: workFSD = (FileStructureDescription) dependentFSDs
1318: .elementAt(exIndex);
1319: if (workFSD.packageName.content
1320: .startsWith(basisPackageName)) {
1321: exIndex++; // ok proceed
1322: } else {
1323: dependentFSDs.removeElementAt(exIndex); // remove it
1324: }
1325: } // while
1326: } // if
1327: } else {
1328:
1329: //ystem.out.println(">fs> is public");
1330:
1331: // Add all files, which depend from the basisFSD
1332: // and any project class and its dependent classes in the parent chain:
1333: for (int k = 0; k < selectedTargetFSDs.length; k++) {
1334: this .addAllFSDsWhichDependFrom(selectedTargetFSDs[k],
1335: dependentFSDs, fsdManager);
1336: }
1337: } //else
1338:
1339: //ystem.out.println(">fs222> SymbolUsageLocationSearch: Search field for " +
1340: // fieldFSDResult.fsd.objectNameWithPosition.content );
1341:
1342: //
1343: // Jedes File in der obigen Liste muss auf Block parsernode level durchsucht werden
1344: // nach relativen oder absoluten Referenzen der Basisklasse und dann nach
1345: // expliziten Methodenaufrufen der obigen Zielmethode.
1346: //
1347: // Zunächst lasse ich die Vererbung beiseite und beruecksichtige nur
1348: // Toplevel-Instanzen mit dynamischen oder statischen Methoden
1349: // also folgende zwei Formen:
1350: // instance.dynamicMethod( ... ) oder Class.StaticMethod( ... )
1351: //
1352: // instance oder Class konnen relativ oder qualifiziert sein.
1353: //
1354: // instance kann Member Attribut oder lokale Variable sein.
1355: //
1356: // Zusätzlich sind auch "verdeckte" Calls möglich:
1357: //
1358: // anotherClassInstance.getMyInstance().dynamicMethod().sayHello()
1359: //
1360: //
1361: FileStructureDescriptionParserTreePostProcessor postProcessor = new FileStructureDescriptionParserTreePostProcessor(
1362: fsdManager);
1363: // Fill all hits into ClassReferenceEntry objects and add them to this vector:
1364: Vector classReferences = new Vector();
1365: if (progressWindow != null) {
1366: progressWindow.setProgressMaxValue(dependentFSDs.size());
1367: }
1368: for (int fsdIndex = 0; fsdIndex < dependentFSDs.size(); fsdIndex++) {
1369: if (progressWindow != null) {
1370: final int progressValue = fsdIndex;
1371: EventQueue.invokeLater(new Runnable() {
1372: public void run() {
1373: progressWindow.setProgressValue(progressValue);
1374: }
1375: });
1376: // Break the search, if the user has pushed the cancel button:
1377: if (progressWindow.getWasCancelled()) {
1378: searchHasBeenCancelledByTheUser = true;
1379: break;
1380: }
1381: try {
1382: Thread.yield();
1383: } catch (Exception e234986) {
1384: }
1385: }
1386:
1387: final FileStructureDescription candidateFSD = (FileStructureDescription) dependentFSDs
1388: .elementAt(fsdIndex);
1389: // Get the associated source text (can be from java files or from jar archives)
1390: final StringBuffer candidateSourceCode = fsdManager
1391: .getJavaSourceForFSD(candidateFSD);
1392: // Get the full parser tree:
1393: final ParserTreeNode compilationUnitNode = this
1394: .getCompilationUnitNodeFor(candidateSourceCode,
1395: candidateFSD.fullyQualifiedClassNameBuffer
1396: .toString());
1397: // For the following scan, the fsd must have the local fields, which usually only
1398: // are parsed for fsd's of sources, which are going to be displayed in the source editor.
1399: // This actions here are made for many fsd's, which of course are not displayed in
1400: // the editor, so we have to update them to have the local fields information:
1401: // Note the two flags:
1402: // create local fields = true ( as mentionned above )
1403: // call dependency scanner = true : Because the dependency fields are cleared
1404: // by the postProcessor, the dependencies
1405: // ALWAYS must be recalculated.
1406: // Because the postprocessor stores
1407: // the compilationrootnode and the fsd in the entries
1408: // sent to the dependency updater, this doesn't
1409: // cost much time:
1410: // This all is done on the same fsd reference.
1411: postProcessor.updatePostProcessParserTree(candidateFSD,
1412: candidateFSD.belongsToProject, compilationUnitNode,
1413: candidateFSD.pathNameBuffer.toString(), true, // create local fields
1414: true); // call dependency scanner
1415: // Now deepscan the tree for occurences of calls of the searched method:
1416: // For any found location (defined by the line and column numbers) we do the same
1417: // like done, when the declaration of the method is searched and see, if we
1418: // land in the targetFSD or not. If we do land in the targetFSD, a call location
1419: // has been found.
1420: this .scanForFieldCallsOf(candidateFSD, compilationUnitNode,
1421: fieldName, classReferences);
1422: } // for
1423:
1424: //ystem.out.println(">fs333> SymbolUsageLocationSearch: Search field for " +
1425: // fieldFSDResult.fsd.objectNameWithPosition.content );
1426:
1427: if (!this .searchHasBeenCancelledByTheUser) {
1428: // Not absolutely required, but more secure, because at least the queue of the
1429: // dependency updater will contain some entries: Force to perform all pending
1430: // entries again:
1431: fsdManager.waitForUpdaters();
1432:
1433: //ystem.out.println(">fs444> SymbolUsageLocationSearch: Search field for " +
1434: // fieldFSDResult.fsd.objectNameWithPosition.content );
1435:
1436: // If the "jump to declaration" procedure returns the methodFSDResult.basisFSD,
1437: // one can add a jump-to-method-call action to the searchresults tree:
1438: Vector searchResultsUserObjectVector = new Vector();
1439: for (int i = 0; i < classReferences.size(); i++) {
1440: final FieldReferenceEntry entry = (FieldReferenceEntry) classReferences
1441: .elementAt(i);
1442: // We need the SourceEditorDocument:
1443: EditableLeafObject leaf = fsdManager
1444: .getJavaSourceEditorLeafForFSD(entry
1445: .getClassDescription());
1446: // On leaf level, one should unload the content, after having loaded and processed it.
1447: // But one shouldn't unload it, if it already was loaded by another one, when this method starts.
1448: // It's not serious, if this doesn't work some times, so no need for synchronization here.
1449: boolean leafWasLoadedInitially = leaf.isContentLoaded();
1450: Object leafContent = leaf.getContent();
1451: if (leafContent instanceof SourceEditorDocument) {
1452: final SourceEditorDocument sourceDoc = (SourceEditorDocument) leafContent;
1453: // Test, if the sound attribute described in fieldFSDResult lies in
1454: // the selectedTargetFSDs, or if this attribute is
1455: // a local attribute, test, if it lies in the currentFSD and if
1456: // the currentLineNumber is in its local scope:
1457: boolean isValidField = false;
1458: if ((fieldFSDResult.fsd.scopeStartLine <= 0)
1459: && (fieldFSDResult.fsd.scopeEndLine <= 0)) {
1460: // It's a MEMBER attribute
1461: isValidField = this
1462: .getIsFieldDeclarationLocatedIn(
1463: sourceDoc, entry,
1464: fieldFSDResult,
1465: selectedTargetFSDs, fsdManager);
1466:
1467: if (!isValidField) {
1468: Log
1469: .Info("getIsFieldDeclarationLocatedIn returned false for "
1470: + entry
1471: .getClassDescription().fullyQualifiedClassNameBuffer
1472: .toString());
1473: }
1474: } else {
1475: // It's a LOCAL attribute - so we don't need the selectedTargetFSDs,
1476: // because only the currentFSD is allowed as basisFSD for possible hits.
1477: isValidField = this
1478: .getIsLocalFieldDeclarationInScope(
1479: sourceDoc, entry,
1480: fieldFSDResult, fsdManager,
1481: currentFSD, currentLineNumber);
1482: if (!isValidField) {
1483: Log
1484: .Info("getIsLocalFieldDeclarationInScope returned false for "
1485: + entry
1486: .getClassDescription().fullyQualifiedClassNameBuffer
1487: .toString());
1488: }
1489: } // else
1490: if (isValidField) {
1491: // Create a SearchResultsFileNodeUserObject and add it to the vector:
1492: final int docPosition = sourceDoc
1493: .getPositionOfStartOfLine(entry
1494: .getStartLine() - 1)
1495: + (entry.getStartColumn() + entry
1496: .getEndColumn()) / 2;
1497: final boolean breakAtPoints = false;
1498: final int[] nearestWordPosition = sourceDoc
1499: .getNearestWordPositionTo(docPosition,
1500: breakAtPoints);
1501: final int startOffset = nearestWordPosition[0];
1502: final int endOffset = nearestWordPosition[1];
1503:
1504: final SearchResultsUserObject resultUserObject = new SearchResultsUserObject(
1505: leaf, entry.getStartLine() - 1,
1506: docPosition, entry.getEndColumn()
1507: - entry.getStartColumn() + 1);
1508:
1509: searchResultsUserObjectVector
1510: .addElement(resultUserObject);
1511: } // if
1512: } // if
1513: else {
1514: Log
1515: .Warn("leafContent as NOT instanceof SourceEditorDocument");
1516: }
1517: // Be careful with unloading: One only is allowed to unload the leaf,
1518: // if it has not been loaded, when this method has started, otherwise we could
1519: // possibly unload a leaf, which currently is displayed in the editor, which
1520: // would cause the editor to crash soon after this.
1521: if (!leafWasLoadedInitially) {
1522: leaf.unloadContent(false); // make memory of this available sooner (gc)
1523: }
1524: } // for
1525:
1526: /*
1527: long elapsedTime = System.currentTimeMillis() - startTime;
1528: Log.Info("elapsedTime= " + elapsedTime );
1529: Log.Info("+ CheckResults: Found " + searchResultsUserObjectVector.size() + " hits.");
1530: */
1531:
1532: // Close and dipose the progressWindow, if it has been created:
1533: if (progressWindow != null) {
1534: EventQueue.invokeLater(new Runnable() {
1535: public void run() {
1536: progressWindow.setVisible(false);
1537: progressWindow.dispose();
1538: }
1539: });
1540: // Give Swing some time right now:
1541: try {
1542: Thread.sleep(88);
1543: } catch (Exception e1) {
1544: }
1545: } // if
1546:
1547: // Tell the searchresults tree to display action-entries for the
1548: // found results, if some were found:
1549: if (searchResultsUserObjectVector.size() > 0) {
1550: elementsHaveBeenFound = true;
1551: SearchResultsUserObject[] searchResultsUserObjects = new SearchResultsUserObject[searchResultsUserObjectVector
1552: .size()];
1553: searchResultsUserObjectVector
1554: .copyInto(searchResultsUserObjects);
1555: this .projectFrame
1556: .setSearchResultsTreeContentWithObjectSearchResults(
1557: searchName, searchResultsUserObjects);
1558: } else {
1559: String title = Language
1560: .Translate("Object Search Results");
1561: String message = Language
1562: .Translate("The object search hasn't found any results.");
1563: JOptionPane
1564: .showMessageDialog(this .projectFrame, message,
1565: title, JOptionPane.INFORMATION_MESSAGE);
1566: }
1567: classReferences.setSize(0); // GC assistance
1568: }
1569: return elementsHaveBeenFound;
1570: } // search_Field_Usage_Locations_In_Thread
1571:
1572: private void addAllFSDsWhichDependFrom(
1573: final FileStructureDescription basisFSD,
1574: final Vector dependentFSDs,
1575: final FileStructureDescriptionManager fsdManager) {
1576:
1577: // Add the basisFSD itself:
1578: this .addUniqueObjectToVector(basisFSD, dependentFSDs);
1579:
1580: // The method is public:
1581: // We only have to scan files, which depend in some way from
1582: // the file given by the topLevelSourceFileFSD.
1583: // This is is absoulutely important: If this information wouldn't be
1584: // available, one could forget that, because searching all files
1585: // in the src,libs and projects takes far too much time and resources.
1586: FileStructureDescription[] allFSDs = fsdManager
1587: .getAllFileStructureDescriptions();
1588: String sourceFileKeyName = basisFSD.fullyQualifiedClassNameBuffer
1589: .toString();
1590: boolean onlySearchInProject = basisFSD.belongsToProject;
1591: FileStructureDescription fsd = null;
1592: for (int index = 0; index < allFSDs.length; index++) {
1593: fsd = allFSDs[index];
1594: // If the basis fsd is in the project, we don't have to search all the libraries too.
1595: // In searches of the libraries too, especially the amount of fsd's which need to be
1596: // compiled always, will increase.
1597: if (fsd.belongsToProject || (!onlySearchInProject)) {
1598: // Add the fsd, if the sourceFileKeyName is among the referenced targets,
1599: // or if the fsd has to be compiled always and therefore possibly
1600: // has dependencies to any file:
1601: if (fsd.hasToBeCompiledAlways) {
1602: this .addUniqueObjectToVector(fsd, dependentFSDs);
1603: //ystem.out.println("Method usage search fsd.hasToBeCompiledAlways: " +
1604: // fsd.fullyQualifiedClassNameBuffer.toString() );
1605: } else {
1606: for (int k = 0; k < fsd.referencedProjectFiles
1607: .size(); k++) {
1608: if (((String) fsd.referencedProjectFiles
1609: .elementAt(k))
1610: .equals(sourceFileKeyName)) {
1611: this .addUniqueObjectToVector(fsd,
1612: dependentFSDs);
1613: break;
1614: }
1615: }
1616: }
1617: } // if
1618: } // for
1619:
1620: // Recur:
1621: // Add all parent files and their dependent files, but only
1622: // as long as they are in the project:
1623: if (basisFSD.super Class_fullyQualifiedClassName.content
1624: .length() > 0) {
1625: // Get that superclass fsd:
1626: final String super ClassQualifier = basisFSD.super Class_fullyQualifiedClassName.content;
1627: // Note: superClass_fullyQualifiedClassName only is qualified in the sense, that
1628: // it's the qualifier as entered in the source. That means, that we still
1629: // must combine it with all import statements :
1630: // Note: For the combination of import statements, it's always the toplevel currentFSD,
1631: // which must be used, also if basisFSD points to a nested fsd.
1632: final String[] inScopePossibleIdentifiers = CodeCompletionUtilities
1633: .CreatePossibleQualifiedClassIdentifiers(basisFSD,
1634: super ClassQualifier);
1635: FileStructureDescription parentFSD = null;
1636: for (int p = 0; p < inScopePossibleIdentifiers.length; p++) {
1637: parentFSD = fsdManager
1638: .searchFSD(inScopePossibleIdentifiers[p]);
1639: if (parentFSD != null) {
1640: break;
1641: }
1642: }
1643: if (parentFSD == null) // happens in presence of syntactical errors in the source
1644: {
1645: /*
1646: Log.Info("No fsd found for key: ");
1647: Log.Info("$" + basisFSD.superClass_fullyQualifiedClassName.content + "$" );
1648: */
1649: } else {
1650: // If it belongs to the project, add it and all its dependent fsd's too:
1651: if (parentFSD.belongsToProject) {
1652: this .addAllFSDsWhichDependFrom(parentFSD,
1653: dependentFSDs, fsdManager);
1654: }
1655: }
1656: }
1657: } // addAllFSDsWhichDependFrom
1658:
1659: /**
1660: * Traces back the method call defined in methodReferenceEntry to
1661: * the location, where the associated method is declared.
1662: * If that declaration point lies inside one the selectedTargetFSDs, true is returned.
1663: */
1664: private boolean getIsMethodDeclarationLocatedIn(
1665: final SourceEditorDocument sourceDoc,
1666: final MethodReferenceEntry methodReferenceEntry,
1667: final SearchMethodFSDResult methodFSDResult,
1668: final FileStructureDescription[] selectedTargetFSDs,
1669: final FileStructureDescriptionManager fsdManager) {
1670: boolean isLocatedInSelectedTargetFSDs = false;
1671: // Get the position of somewhere in the middle of the methodname:
1672:
1673: // Important: Use the same document methods, as if the user would have rightclicked
1674: // the methodname with the mouse. This way, changes on these searchroutines
1675: // automatically change this search here too.
1676: // See SourceEditorDocument.processCurrentMousePosition().
1677: // The goal is, that we need the optional qualifiers before the methodname too
1678: // for locating the declaration of that method.
1679: // Take the average column position as doc position:
1680: final int docPosition = sourceDoc
1681: .getPositionOfStartOfLine(methodReferenceEntry
1682: .getStartLine() - 1)
1683: + (methodReferenceEntry.getStartColumn() + methodReferenceEntry
1684: .getEndColumn()) / 2;
1685: final boolean breakAtPoints = false;
1686: final int[] nearestWordPosition = sourceDoc
1687: .getNearestWordPositionTo(docPosition, breakAtPoints);
1688: final int startOffset = nearestWordPosition[0];
1689: final int endOffset = nearestWordPosition[1];
1690: try {
1691: final String searchIdentifier = sourceDoc.getText(
1692: startOffset, endOffset - startOffset + 1);
1693:
1694: //ystem.out.println("");
1695: //ystem.out.println("getIsMethod.. searchIdentifier= <" + searchIdentifier + ">");
1696:
1697: // Target Containers for the objectSearch results :
1698: Vector fieldFSDTargetResultsVector = new Vector();
1699: Vector methodFSDTargetResultsVector = new Vector();
1700: Vector classFSDTargetResultsVector = new Vector();
1701:
1702: ObjectSearch objectSearch = new ObjectSearch(docPosition,
1703: sourceDoc, this .projectFrame.getEditorPanel(),
1704: methodReferenceEntry.getClassDescription(),
1705: fsdManager);
1706: objectSearch.doSearch(searchIdentifier,
1707: fieldFSDTargetResultsVector,
1708: methodFSDTargetResultsVector,
1709: classFSDTargetResultsVector);
1710: // Now, the objectSearch results have been added to the passed vectors.
1711:
1712: // Translate the results into arrays :
1713: SearchFieldFSDResult[] searchFieldFSDTargetResults = new SearchFieldFSDResult[fieldFSDTargetResultsVector
1714: .size()];
1715: fieldFSDTargetResultsVector
1716: .copyInto(searchFieldFSDTargetResults);
1717: SearchMethodFSDResult[] searchMethodFSDTargetResults = new SearchMethodFSDResult[methodFSDTargetResultsVector
1718: .size()];
1719: methodFSDTargetResultsVector
1720: .copyInto(searchMethodFSDTargetResults);
1721:
1722: // Invert the order of class entries :
1723: SearchFSDResult[] searchFSDTargetResults = new SearchFSDResult[classFSDTargetResultsVector
1724: .size()];
1725: for (int i = 0; i < searchFSDTargetResults.length; i++) {
1726: searchFSDTargetResults[i] = (SearchFSDResult) classFSDTargetResultsVector
1727: .elementAt(searchFSDTargetResults.length - i
1728: - 1);
1729: }
1730:
1731: // Here we actually dont need the vector element entry functionality as jump actions,
1732: // like used in the EditorTextSearch objects.
1733: // Here, we only test, if the jumps would land in the basis FSD or not.
1734: // If they do, the associated entry is a hit = is a method call, which has the
1735: // basis method as target:
1736:
1737: /* ----------- Debug Output Start ------------
1738: Log.Info("SymbolUsageLocationSearch:getIsMethod.. #searchFieldFSDResults = " +
1739: searchFieldFSDTargetResults.length );
1740: if( searchFieldFSDTargetResults.length > 0 )
1741: {
1742: Log.Info("which are:");
1743: for( int p=0; p < searchFieldFSDTargetResults.length; p++ )
1744: {
1745: final String name = searchFieldFSDTargetResults[p].fsd.objectNameWithPosition.content;
1746: Log.Info("- " + name);
1747: }
1748: }
1749: Log.Info("getIsMethod.. #searchMethodFSDResults = " +
1750: searchMethodFSDTargetResults.length );
1751: if( searchMethodFSDTargetResults.length > 0 )
1752: {
1753: Log.Info("which are:");
1754: for( int p=0; p < searchMethodFSDTargetResults.length; p++ )
1755: {
1756: final String name = searchMethodFSDTargetResults[p].fsd.name.content;
1757: final String parentFSDname = searchMethodFSDTargetResults[p].basisFSD.className.content;
1758: Log.Info("- " + name + " in fsd: " + parentFSDname );
1759: }
1760: }
1761: Log.Info("SymbolUsageLocationSearch:getIsMethod.. #searchFSDResults = " +
1762: searchFSDTargetResults.length );
1763: if( searchFSDTargetResults.length > 0 )
1764: {
1765: Log.Info("which are:");
1766: for( int p=0; p < searchFSDTargetResults.length; p++ )
1767: {
1768: final String name = searchFSDTargetResults[p].fsd.className.content;
1769: Log.Info("- " + name);
1770: }
1771: }
1772: ----------- Debug Output End ------------ */
1773:
1774: // The selected sources containing the searched method are given by the array
1775: // selectedTargetFSDs.
1776: // searchMethodFSDTargetResults[i]
1777: // Now the fsd's, which describe files [containing the searched method]
1778: // and which are selected for the search, are given by the
1779: // selectedTargetFSDs fsd array.
1780: // With other words: Any methodFSDResult result, which has its basis fsd
1781: // equal to one of the selectedTargetFSDs is a hit:
1782: String s1, s2;
1783: for (int i = 0; i < searchMethodFSDTargetResults.length; i++) {
1784: for (int k = 0; k < selectedTargetFSDs.length; k++) {
1785: s1 = searchMethodFSDTargetResults[i].basisFSD.fullyQualifiedClassNameBuffer
1786: .toString();
1787: s2 = selectedTargetFSDs[k].fullyQualifiedClassNameBuffer
1788: .toString();
1789:
1790: //ystem.out.println("CMP> " + s1 + " against " + s2 );
1791:
1792: if (s1.equals(s2)) {
1793: isLocatedInSelectedTargetFSDs = true;
1794: }
1795: }
1796: } // for
1797: s1 = null;
1798: s2 = null;
1799: } catch (Exception e) {
1800: Log
1801: .Info("Exception catched. This exception is not serious.");
1802: // Log.Error( e );
1803: }
1804: return isLocatedInSelectedTargetFSDs;
1805: } // getIsMethodDeclarationLocatedIn
1806:
1807: /**
1808: * Like getIsMethodDeclarationLocatedIn(), but this one works for attributes.
1809: * Traces back the field call defined in fieldReferenceEntry to
1810: * the location, where the associated field is declared.
1811: * If that declaration point lies inside one the selectedTargetFSDs, true is returned.
1812: * Note: For LOCAL attributes, one has to call getIsLocalFieldDeclarationInScope()
1813: * instead of this method.
1814: */
1815: private boolean getIsFieldDeclarationLocatedIn(
1816: final SourceEditorDocument sourceDoc,
1817: final FieldReferenceEntry fieldReferenceEntry,
1818: final SearchFieldFSDResult fieldFSDResult,
1819: final FileStructureDescription[] selectedTargetFSDs,
1820: final FileStructureDescriptionManager fsdManager) {
1821:
1822: //ystem.out.println("Calling getIsFieldDeclarationLocatedIn for " +
1823: // fieldFSDResult.fsd.objectNameWithPosition.content );
1824:
1825: boolean isLocatedInSelectedTargetFSDs = false;
1826: // Get the position of somewhere in the middle of the methodname:
1827:
1828: // Important: Use the same document methods, as if the user would have rightclicked
1829: // the methodname with the mouse. This way, changes on these searchroutines
1830: // automatically change this search here too.
1831: // See SourceEditorDocument.processCurrentMousePosition().
1832: // The goal is, that we need the optional qualifiers before the methodname too
1833: // for locating the declaration of that method.
1834: // Take the average column position as doc position:
1835: final int docPosition = sourceDoc
1836: .getPositionOfStartOfLine(fieldReferenceEntry
1837: .getStartLine() - 1)
1838: + (fieldReferenceEntry.getStartColumn() + fieldReferenceEntry
1839: .getEndColumn()) / 2;
1840: final boolean breakAtPoints = false;
1841: final int[] nearestWordPosition = sourceDoc
1842: .getNearestWordPositionTo(docPosition, breakAtPoints);
1843: final int startOffset = nearestWordPosition[0];
1844: final int endOffset = nearestWordPosition[1];
1845: try {
1846: final String searchIdentifier = sourceDoc.getText(
1847: startOffset, endOffset - startOffset + 1);
1848:
1849: //ystem.out.println("SymbolUsageLocationSearch:getIsField.. searchIdentifier= <" + searchIdentifier + ">");
1850:
1851: // Target Containers for the objectSearch results :
1852: Vector fieldFSDTargetResultsVector = new Vector();
1853: Vector methodFSDTargetResultsVector = new Vector();
1854: Vector classFSDTargetResultsVector = new Vector();
1855:
1856: // If the symbol contains points, we add items for
1857: // all levels from the whole qualifier down to the root qualifier.
1858: String[] searchQualifiers = StringUtilities.SplitString(
1859: searchIdentifier, ".");
1860:
1861: //ystem.out.println("SymbolUsageLocationSearch: fieldName= " + fieldReferenceEntry.getFieldName() );
1862:
1863: // For the field search, we must start the ObjectSearch multiple times for
1864: // multiple searchQualifiers:
1865: // The first call is done for searchQualifiers[0] alone and for each following call
1866: // the following searchQualifiers element is added:
1867: // Call 1 : searchQualifiers[0]
1868: // Call 2 : searchQualifiers[0] + "." + searchQualifiers[1]
1869: // and so on.
1870: // This way, attribute usages in qualified terms are foung too.
1871: // Example: x.getY().myAttribute.getZ() -> here, myAtribute will be found,
1872: // when the object search is started with the first three searchQualifiers elements.
1873: ObjectSearch objectSearch = new ObjectSearch(docPosition,
1874: sourceDoc, this .projectFrame.getEditorPanel(),
1875: fieldReferenceEntry.getClassDescription(),
1876: fsdManager);
1877: for (int i = 0; i < searchQualifiers.length; i++) {
1878: StringBuffer cumulativeIdentifier = new StringBuffer("");
1879: for (int k = 0; k < i + 1; k++) {
1880: cumulativeIdentifier.append(searchQualifiers[k]);
1881: if (k < i)
1882: cumulativeIdentifier.append(".");
1883: }
1884: objectSearch.doSearch(cumulativeIdentifier.toString(),
1885: fieldFSDTargetResultsVector,
1886: methodFSDTargetResultsVector,
1887: classFSDTargetResultsVector);
1888: }
1889: // Now, the objectSearch results have been added to the passed vectors.
1890:
1891: // Translate the results into arrays :
1892: SearchFieldFSDResult[] searchFieldFSDTargetResults = new SearchFieldFSDResult[fieldFSDTargetResultsVector
1893: .size()];
1894: fieldFSDTargetResultsVector
1895: .copyInto(searchFieldFSDTargetResults);
1896: SearchMethodFSDResult[] searchMethodFSDTargetResults = new SearchMethodFSDResult[methodFSDTargetResultsVector
1897: .size()];
1898: methodFSDTargetResultsVector
1899: .copyInto(searchMethodFSDTargetResults);
1900:
1901: // Invert the order of class entries :
1902: SearchFSDResult[] searchFSDTargetResults = new SearchFSDResult[classFSDTargetResultsVector
1903: .size()];
1904: for (int i = 0; i < searchFSDTargetResults.length; i++) {
1905: searchFSDTargetResults[i] = (SearchFSDResult) classFSDTargetResultsVector
1906: .elementAt(searchFSDTargetResults.length - i
1907: - 1);
1908: }
1909:
1910: // Here we actually dont need the vector element entry functionality as jump actions,
1911: // like used in the EditorTextSearch objects.
1912: // Here, we only test, if the jumps would land in the basis FSD or not.
1913: // If they do, the assoviated entry is a hit = is a method call, which has the
1914: // basis method as target:
1915:
1916: /* ---------- Debug Output Start -----------
1917: Log.Info("SymbolUsageLocationSearch:getIsField.. #searchFieldFSDResults = " +
1918: searchFieldFSDTargetResults.length );
1919: if( searchFieldFSDTargetResults.length > 0 )
1920: {
1921: Log.Info("which are:");
1922: for( int p=0; p < searchFieldFSDTargetResults.length; p++ )
1923: {
1924: final String name = searchFieldFSDTargetResults[p].fsd.objectNameWithPosition.content;
1925: Log.Info("- " + name);
1926: }
1927: }
1928: Log.Info("SymbolUsageLocationSearch:getIsField.. #searchMethodFSDResults = " +
1929: searchMethodFSDTargetResults.length );
1930: if( searchMethodFSDTargetResults.length > 0 )
1931: {
1932: Log.Info("which are:");
1933: for( int p=0; p < searchMethodFSDTargetResults.length; p++ )
1934: {
1935: final String name = searchMethodFSDTargetResults[p].fsd.name.content;
1936: final String parentFSDname = searchMethodFSDTargetResults[p].basisFSD.className.content;
1937: Log.Info("- " + name + " in fsd: " + parentFSDname );
1938: }
1939: }
1940: Log.Info("SymbolUsageLocationSearch:getIsField.. #searchFSDResults = " +
1941: searchFSDTargetResults.length );
1942: if( searchFSDTargetResults.length > 0 )
1943: {
1944: Log.Info("which are:");
1945: for( int p=0; p < searchFSDTargetResults.length; p++ )
1946: {
1947: final String name = searchFSDTargetResults[p].fsd.className.content;
1948: Log.Info("- " + name);
1949: }
1950: }
1951: ---------- Debug Output End ----------- */
1952:
1953: // The selected sources containing the searched method are given by the array
1954: // selectedTargetFSDs.
1955: // searchMethodFSDTargetResults[i]
1956: // Now the fsd's, which describe files [containing the searched method]
1957: // and which are selected for the search, are given by the
1958: // selectedTargetFSDs fsd array.
1959: // With other words: Any fieldFSDResult result, which has its basis fsd
1960: // equal to one of the selectedTargetFSDs is a hit:
1961: String s1, s2;
1962: for (int i = 0; i < searchFieldFSDTargetResults.length; i++) {
1963: for (int k = 0; k < selectedTargetFSDs.length; k++) {
1964: s1 = searchFieldFSDTargetResults[i].basisFSD.fullyQualifiedClassNameBuffer
1965: .toString();
1966: s2 = selectedTargetFSDs[k].fullyQualifiedClassNameBuffer
1967: .toString();
1968: if (s1.equals(s2)) {
1969: isLocatedInSelectedTargetFSDs = true;
1970: break;
1971: }
1972: } // for
1973: } // for
1974: s1 = null;
1975: s2 = null;
1976: } catch (Exception e) {
1977: Log
1978: .Info("Exception catched. This exception is not serious.");
1979: // Log.Error( e );
1980: }
1981: return isLocatedInSelectedTargetFSDs;
1982: } // getIsFieldDeclarationLocatedIn
1983:
1984: /**
1985: * Like getIsFieldDeclarationLocatedIn(), but this one is made for
1986: * LOCAL attributes.
1987: * If this attribute is a local attribute, test, if it lies in the currentFSD and if
1988: * the currentLineNumber is in its local scope.
1989: */
1990: private boolean getIsLocalFieldDeclarationInScope(
1991: final SourceEditorDocument sourceDoc,
1992: final FieldReferenceEntry fieldReferenceEntry,
1993: final SearchFieldFSDResult fieldFSDResult,
1994: final FileStructureDescriptionManager fsdManager,
1995: final FileStructureDescription currentFSD,
1996: final int currentLineNumber) {
1997:
1998: if (fieldFSDResult == null) {
1999: Log.Warn("fieldFSDResult == null");
2000: }
2001: if (fieldFSDResult.fsd == null) {
2002: Log.Warn("fieldFSDResult.fsd == null");
2003: }
2004: if (fieldFSDResult.fsd.objectNameWithPosition == null) {
2005: Log
2006: .Warn("fieldFSDResult.fsd.objectNameWithPosition == null");
2007: Log.Warn("for fsd " + fieldFSDResult.fsd.simpleClassName);
2008: }
2009:
2010: // Log.Info("Calling getIsLocalFieldDeclarationInScope for " +
2011: // fieldFSDResult.fsd.objectNameWithPosition.content );
2012:
2013: boolean isLocatedIncurrentFSDAndIsInScope = false;
2014: // Get the position of somewhere in the middle of the methodname:
2015:
2016: // Important: Use the same document methods, as if the user would have rightclicked
2017: // the methodname with the mouse. This way, changes on these searchroutines
2018: // automatically change this search here too.
2019: // See SourceEditorDocument.processCurrentMousePosition().
2020: // The goal is, that we need the optional qualifiers before the methodname too
2021: // for locating the declaration of that method.
2022: // Take the average column position as doc position:
2023: final int docPosition = sourceDoc
2024: .getPositionOfStartOfLine(fieldReferenceEntry
2025: .getStartLine() - 1)
2026: + (fieldReferenceEntry.getStartColumn() + fieldReferenceEntry
2027: .getEndColumn()) / 2;
2028: final boolean breakAtPoints = false;
2029: final int[] nearestWordPosition = sourceDoc
2030: .getNearestWordPositionTo(docPosition, breakAtPoints);
2031: final int startOffset = nearestWordPosition[0];
2032: final int endOffset = nearestWordPosition[1];
2033: try {
2034: final String searchIdentifier = sourceDoc.getText(
2035: startOffset, endOffset - startOffset + 1);
2036:
2037: //ystem.out.println("SymbolUsageLocationSearch:getIsField.. searchIdentifier= <" + searchIdentifier + ">");
2038:
2039: // Target Containers for the objectSearch results :
2040: Vector fieldFSDTargetResultsVector = new Vector();
2041: Vector methodFSDTargetResultsVector = new Vector();
2042: Vector classFSDTargetResultsVector = new Vector();
2043:
2044: // If the symbol contains points, we add items for
2045: // all levels from the whole qualifier down to the root qualifier.
2046: String[] searchQualifiers = StringUtilities.SplitString(
2047: searchIdentifier, ".");
2048:
2049: //ystem.out.println("SymbolUsageLocationSearch: fieldName= " + fieldReferenceEntry.getFieldName() );
2050:
2051: // For the field search, we must start the ObjectSearch multiple times for
2052: // multiple searchQualifiers:
2053: // The first call is done for searchQualifiers[0] alone and for each following call
2054: // the following searchQualifiers element is added:
2055: // Call 1 : searchQualifiers[0]
2056: // Call 2 : searchQualifiers[0] + "." + searchQualifiers[1]
2057: // and so on.
2058: // This way, attribute usages in qualified terms are foung too.
2059: // Example: x.getY().myAttribute.getZ() -> here, myAtribute will be found,
2060: // when the object search is started with the first three searchQualifiers elements.
2061: ObjectSearch objectSearch = new ObjectSearch(docPosition,
2062: sourceDoc, this .projectFrame.getEditorPanel(),
2063: fieldReferenceEntry.getClassDescription(),
2064: fsdManager);
2065: for (int i = 0; i < searchQualifiers.length; i++) {
2066: StringBuffer cumulativeIdentifier = new StringBuffer("");
2067: for (int k = 0; k < i + 1; k++) {
2068: cumulativeIdentifier.append(searchQualifiers[k]);
2069: if (k < i)
2070: cumulativeIdentifier.append(".");
2071: }
2072: objectSearch.doSearch(cumulativeIdentifier.toString(),
2073: fieldFSDTargetResultsVector,
2074: methodFSDTargetResultsVector,
2075: classFSDTargetResultsVector);
2076: }
2077: // Now, the objectSearch results have been added to the passed vectors.
2078:
2079: // Translate the results into arrays :
2080: SearchFieldFSDResult[] searchFieldFSDTargetResults = new SearchFieldFSDResult[fieldFSDTargetResultsVector
2081: .size()];
2082: fieldFSDTargetResultsVector
2083: .copyInto(searchFieldFSDTargetResults);
2084: SearchMethodFSDResult[] searchMethodFSDTargetResults = new SearchMethodFSDResult[methodFSDTargetResultsVector
2085: .size()];
2086: methodFSDTargetResultsVector
2087: .copyInto(searchMethodFSDTargetResults);
2088:
2089: // Invert the order of class entries :
2090: SearchFSDResult[] searchFSDTargetResults = new SearchFSDResult[classFSDTargetResultsVector
2091: .size()];
2092: for (int i = 0; i < searchFSDTargetResults.length; i++) {
2093: searchFSDTargetResults[i] = (SearchFSDResult) classFSDTargetResultsVector
2094: .elementAt(searchFSDTargetResults.length - i
2095: - 1);
2096: }
2097:
2098: // Here we actually dont need the vector element entry functionality as jump actions,
2099: // like used in the EditorTextSearch objects.
2100: // Here, we only test, if the jumps would land in the basis FSD or not.
2101: // If they do, the assoviated entry is a hit = is a method call, which has the
2102: // basis method as target:
2103:
2104: /* ----------- Debug Output Start ------------
2105: Log.Info("SymbolUsageLocationSearch:getIsLocalFieldDeclarationInScope.. #searchFieldFSDResults = " +
2106: searchFieldFSDTargetResults.length );
2107: if( searchFieldFSDTargetResults.length > 0 )
2108: {
2109: Log.Info("which are:");
2110: for( int p=0; p < searchFieldFSDTargetResults.length; p++ )
2111: {
2112: final String name = searchFieldFSDTargetResults[p].fsd.objectNameWithPosition.content;
2113: Log.Info("- " + name);
2114: }
2115: }
2116: Log.Info("SymbolUsageLocationSearch:getIsLocalFieldDeclarationInScope.. #searchMethodFSDResults = " +
2117: searchMethodFSDTargetResults.length );
2118: if( searchMethodFSDTargetResults.length > 0 )
2119: {
2120: Log.Info("which are:");
2121: for( int p=0; p < searchMethodFSDTargetResults.length; p++ )
2122: {
2123: final String name = searchMethodFSDTargetResults[p].fsd.name.content;
2124: final String parentFSDname = searchMethodFSDTargetResults[p].basisFSD.className.content;
2125: Log.Info("- " + name + " in fsd: " + parentFSDname );
2126: }
2127: }
2128: Log.Info("SymbolUsageLocationSearch:getIsLocalFieldDeclarationInScope.. #searchFSDResults = " +
2129: searchFSDTargetResults.length );
2130: if( searchFSDTargetResults.length > 0 )
2131: {
2132: Log.Info("which are:");
2133: for( int p=0; p < searchFSDTargetResults.length; p++ )
2134: {
2135: final String name = searchFSDTargetResults[p].fsd.className.content;
2136: Log.Info("- " + name);
2137: }
2138: }
2139: ----------- Debug Output End ------------ */
2140:
2141: // The selected sources containing the searched attribute are given by the array
2142: // selectedTargetFSDs.
2143: // searchMethodFSDTargetResults[i]
2144: // Special for LOCAL attribute search:
2145: // basisFSD must be the currentFSD
2146: String s1, s2;
2147: for (int i = 0; i < searchFieldFSDTargetResults.length; i++) {
2148: s1 = searchFieldFSDTargetResults[i].basisFSD.fullyQualifiedClassNameBuffer
2149: .toString();
2150: s2 = currentFSD.fullyQualifiedClassNameBuffer
2151: .toString();
2152:
2153: //Log.Info("Check1 " + s1 + " against " + s2 );
2154:
2155: if (s1.equals(s2)) {
2156:
2157: /* Debug
2158: Log.Info("Check1 [2] equal scopeStartLine 1");
2159: boolean aa = ( searchFieldFSDTargetResults[i].fsd.scopeStartLine > 0 );
2160: boolean bb = ( searchFieldFSDTargetResults[i].fsd.scopeEndLine > 0 );
2161: Log.Info("Check1 [2] aa= " + aa + " bb = " + bb);
2162: */
2163:
2164: // The basisFSD of searchFieldFSDTargetResults[i] is the currentFSD, but
2165: // a class can have declared local attributes of the same name multiple
2166: // times, always with different scopes. The scopes cannot overlap, but they
2167: // either don't share anything, or one contains the other completely.
2168: // So check the scopes:
2169: if ((searchFieldFSDTargetResults[i].fsd.scopeStartLine > 0)
2170: && (searchFieldFSDTargetResults[i].fsd.scopeEndLine > 0)) {
2171: // scope numbers are one based, so inrement the currentLineNumber:
2172: final int currentLineNumberOneBased = currentLineNumber + 1;
2173:
2174: /* Debug
2175: Log.Info("Check1 [3] check against linenumber");
2176: Log.Info("Check1 [3] scopeStartLine= " +
2177: searchFieldFSDTargetResults[i].fsd.scopeStartLine);
2178: Log.Info("Check1 [3] scopeEndLine= " +
2179: searchFieldFSDTargetResults[i].fsd.scopeEndLine);
2180: Log.Info("Check1 [3] currentLineNumberOneBased= " +
2181: currentLineNumberOneBased);
2182: */
2183:
2184: // It's local, so check scopes and if they are different,
2185: // clear isLocatedInSelectedTargetFSDs again.
2186: if ((searchFieldFSDTargetResults[i].fsd.scopeStartLine <= currentLineNumberOneBased)
2187: && (searchFieldFSDTargetResults[i].fsd.scopeEndLine >= currentLineNumberOneBased)) {
2188: //Log.Info("isLocatedIncurrentFSDAndIsInScope[1]");
2189: isLocatedIncurrentFSDAndIsInScope = true;
2190: break;
2191: } else {
2192: isLocatedIncurrentFSDAndIsInScope = false;
2193: }
2194: } // if
2195: } // if
2196:
2197: //Log.Info("Check1 negative");
2198:
2199: } // for
2200: s1 = null;
2201: s2 = null;
2202: } catch (Exception e) {
2203: Log
2204: .Info("Catched an exception. This exception is not serious.");
2205: Log.Warn(e);
2206: }
2207:
2208: //Log.Info("returns with success= " +
2209: // isLocatedIncurrentFSDAndIsInScope );
2210:
2211: return isLocatedIncurrentFSDAndIsInScope;
2212: } // getIsLocalFieldDeclarationInScope
2213:
2214: private boolean getIsStringContainedIn(String s, String[] a) {
2215: boolean isContained = false;
2216: for (int i = 0; i < a.length; i++) {
2217: if (a[i].equals(s)) {
2218: isContained = true;
2219: break;
2220: }
2221: }
2222: return isContained;
2223: }
2224:
2225: /**
2226: * Scans the passed fsd for calling locations of the
2227: * method defined by the passed methodFSDResult.
2228: */
2229: public void scanForMethodCallsOf(
2230: final FileStructureDescription fsd,
2231: final DefaultMutableTreeNode javaCCBasisNode,
2232: final String methodName, final Vector classReferences) {
2233: // Simple first task:
2234: // Search the javac tree after "LocalVariableDeclaration" nodes
2235: // in constructor as well as method nodes.
2236: // Then call a worker method, which parses these
2237: // LocalVariableDeclaration, creates (or updates) ReferencedFileEntry
2238: // classes and adds them to the referencedProjectFiles vector
2239: // of the passed fsd:
2240:
2241: // NOTE: We do NOT include dependencies of the parent tree or
2242: // implemented interface tree, because this can go out of sync easily.
2243: // These dependencies are added on demand in fsdManager.getDependentFilePathesOf()
2244: // right before the dependent files are added to the compilerlists.
2245:
2246: // Collect all "TypeDeclaration" nodes, and deepscan for nodes named:
2247: // 1.1 - LocalVariableDeclaration
2248: // 1.2 - FormalParameters
2249: // 1.3 - FieldDeclaration
2250: // 1.4 - ClassReference sequences in static and dynamic reference sequences
2251: // like a.getB().getC().getD() dynamic, or
2252: // A.getB().getC().getD() static
2253:
2254: // NOTE: For a simple class, we only have one TypeDeclaration node at
2255: // level zero. Having multiple TypeDeclaration nodes at this level
2256: // means, we have some inner classes at toplevel, which isn't
2257: // standard but somehow allowed.
2258: // In the fsd postprocessor this is properly decoded. The inner class
2259: // objects are filled into the inner class fsd's.
2260: // However for the reference scan, inner class structures play no role,
2261: // so we put all reference links into the toplevel fsd, which
2262: // stands for the sourcefile.
2263:
2264: // classReferences: Holds statements, which reference classes. They can occure
2265: // anywhere (in for loops, in comparisons..) in local blocks as statements,
2266: // which return void, or they can occure in the *RIGHT SIDE* of all declarations
2267: // described above.
2268:
2269: // Fill them:
2270: // The basisNode = CompilationUnit isn't interesting, so get its children :
2271: final DefaultMutableTreeNode[] basisNodeChildren = this
2272: .getChildren(javaCCBasisNode);
2273: for (int basisNodeIndex = 0; basisNodeIndex < basisNodeChildren.length; basisNodeIndex++) {
2274: // Nodes have String user objects:
2275: final DefaultMutableTreeNode this Child = basisNodeChildren[basisNodeIndex];
2276: final Object userObject = this Child.getUserObject();
2277: if (userObject instanceof Integer) {
2278: // Integer reference comparison is ok here.
2279: if ((Integer) userObject == ParserOutputProcessor.NodeForTypeDeclaration) {
2280: // Get the ClassDeclaration children:
2281: DefaultMutableTreeNode[] classDeclarationNodes = this
2282: .getAllChildNodesWithName(
2283: this Child,
2284: ParserOutputProcessor.NodeForClassOrInterfaceDeclaration);
2285: for (int classDecIndex = 0; classDecIndex < classDeclarationNodes.length; classDecIndex++) {
2286: // Get the ClassBody node children:
2287: DefaultMutableTreeNode[] classBodyNodes = this
2288: .getAllChildNodesWithName(
2289: classDeclarationNodes[classDecIndex],
2290: ParserOutputProcessor.NodeForClassOrInterfaceBody);
2291: for (int classBodyIndex = 0; classBodyIndex < classBodyNodes.length; classBodyIndex++) {
2292: // Get the ClassBodyDeclaration node children:
2293: DefaultMutableTreeNode[] classBodyDeclarationNodes = this
2294: .getAllChildNodesWithName(
2295: classBodyNodes[classBodyIndex],
2296: ParserOutputProcessor.NodeForClassOrInterfaceBodyDeclaration);
2297: for (int classBodyDeclarationIndex = 0; classBodyDeclarationIndex < classBodyDeclarationNodes.length; classBodyDeclarationIndex++) {
2298: // The children of the classBodyDeclarationNodes are
2299: // FieldDeclaration, ConstructorDeclaration or MethodDeclaration nodes.
2300: final DefaultMutableTreeNode cbdNode = classBodyDeclarationNodes[classBodyDeclarationIndex];
2301: // The following calls already perform a few simple filterings :
2302: this .deepScanForClassMethodReferences(
2303: fsd, classReferences, cbdNode,
2304: methodName);
2305: }
2306: }
2307: } // for classDecIndex
2308: } // if
2309: } // if
2310: } // for basisNodeIndex
2311: } // scanForMethodCallsOf
2312:
2313: /**
2314: * Scans for the "left sides" and void statements and additionally
2315: * prefilters the raw results.
2316: * See explanations in scanReferencedObjects.
2317: */
2318: private void deepScanForClassMethodReferences(
2319: final FileStructureDescription candidateFSD,
2320: final Vector targetVector,
2321: final DefaultMutableTreeNode classBodyChildNode,
2322: final String methodName) {
2323: // Deepscan for PrimaryExpression nodes, which have children of the form
2324: // PrimaryPrefix followed by one or multiple PrimarySuffix nodes,
2325: // where the PrimaryPrefix node does *NOT* contain an AllocationExpression node.
2326: //
2327: // NOTE: There are PrimaryExpression nodes, which contain
2328: // an PrimaryPrefix node with an AllocationExpression childnode, but these ones are scanned by the
2329: // the special FieldDeclaration scan in scanReferencedObjects(), where they catch the type
2330: // of the attribute and collect it, if it's not a simple type or the type of an inner class.
2331: // Note: The last parameter treescan=true is required. This onecauses the scan to
2332: // continue reqursion after each hit, so it catches all objects in the tree.
2333: // Example: for the expression a.getx( b.getB() ), it will generate TWO entries:
2334: // 1) a.getx( b.getB() ) [=the full expression]
2335: // 2) b.getB() [=the child in the tree]
2336: //
2337: Vector primaryExpressionNodes = new Vector();
2338: this
2339: .deepScanForNodesWithName(primaryExpressionNodes,
2340: classBodyChildNode,
2341: ParserOutputProcessor.NodeForPrimaryExpression,
2342: true /* treescan */);
2343: for (int i = 0; i < primaryExpressionNodes.size(); i++) {
2344: final DefaultMutableTreeNode this PrimaryExpressionNode = (DefaultMutableTreeNode) primaryExpressionNodes
2345: .elementAt(i);
2346: // Only continue, if it has at least one PrimaryPrefix node:
2347: boolean containsPrimaryPrefixNode = false;
2348: for (int childIndex = 0; childIndex < this PrimaryExpressionNode
2349: .getChildCount(); childIndex++) {
2350: final DefaultMutableTreeNode this Child = (DefaultMutableTreeNode) this PrimaryExpressionNode
2351: .getChildAt(childIndex);
2352: if (this Child.getUserObject() instanceof Integer) // it's a node
2353: {
2354: final Integer this NodeNameIdentifier = (Integer) this Child
2355: .getUserObject();
2356: // reference comparison is ok here.
2357: if (this NodeNameIdentifier == ParserOutputProcessor.NodeForPrimaryPrefix) {
2358: // Ok, it contains a PrimaryPrefix node, so we use scan the
2359: // primary expression node:
2360: containsPrimaryPrefixNode = true;
2361: break;
2362: }
2363: }
2364: } // childIndex
2365: if (containsPrimaryPrefixNode) {
2366: final MethodReferenceEntry entry = this
2367: .scanPrimaryExpressionForMethodCalls(
2368: candidateFSD,
2369: this PrimaryExpressionNode, methodName);
2370: if (entry != null) {
2371: this .addUniqueMethodReferenceEntryToVector(entry,
2372: targetVector);
2373: }
2374: }
2375: } // for i
2376: } // deepScanForClassMethodReferences
2377:
2378: /**
2379: * Like scanForMethodCallsOf(), but works for member attributes.
2380: */
2381: public void scanForFieldCallsOf(final FileStructureDescription fsd,
2382: final DefaultMutableTreeNode javaCCBasisNode,
2383: final String fieldName, final Vector classReferences) {
2384: // Identifier deep scan for left and right sides.
2385: // The basisNode = CompilationUnit isn't interesting, so get its children :
2386: final DefaultMutableTreeNode[] basisNodeChildren = this
2387: .getChildren(javaCCBasisNode);
2388: for (int basisNodeIndex = 0; basisNodeIndex < basisNodeChildren.length; basisNodeIndex++) {
2389: // Nodes have String user objects:
2390: final DefaultMutableTreeNode this Child = basisNodeChildren[basisNodeIndex];
2391: final Object userObject = this Child.getUserObject();
2392: if (userObject instanceof Integer) {
2393: // Integer reference comparison is ok here.
2394: if ((Integer) userObject == ParserOutputProcessor.NodeForTypeDeclaration) {
2395: // Get the ClassDeclaration children:
2396: DefaultMutableTreeNode[] classDeclarationNodes = this
2397: .getAllChildNodesWithName(
2398: this Child,
2399: ParserOutputProcessor.NodeForClassOrInterfaceDeclaration);
2400: for (int classDecIndex = 0; classDecIndex < classDeclarationNodes.length; classDecIndex++) {
2401: // Get the ClassBody node children:
2402: DefaultMutableTreeNode[] classBodyNodes = this
2403: .getAllChildNodesWithName(
2404: classDeclarationNodes[classDecIndex],
2405: ParserOutputProcessor.NodeForClassOrInterfaceBody);
2406: for (int classBodyIndex = 0; classBodyIndex < classBodyNodes.length; classBodyIndex++) {
2407: // Get the ClassBodyDeclaration node children:
2408: DefaultMutableTreeNode[] classBodyDeclarationNodes = this
2409: .getAllChildNodesWithName(
2410: classBodyNodes[classBodyIndex],
2411: ParserOutputProcessor.NodeForClassOrInterfaceBodyDeclaration);
2412: for (int classBodyDeclarationIndex = 0; classBodyDeclarationIndex < classBodyDeclarationNodes.length; classBodyDeclarationIndex++) {
2413: // The children of the classBodyDeclarationNodes are
2414: // FieldDeclaration, ConstructorDeclaration or MethodDeclaration nodes.
2415: final DefaultMutableTreeNode cbdNode = classBodyDeclarationNodes[classBodyDeclarationIndex];
2416: // The following calls already perform a few simple filterings :
2417: this .deepScanForClassFieldReferences(
2418: fsd, classReferences, cbdNode,
2419: fieldName);
2420: }
2421: }
2422: } // for classDecIndex
2423: } // if
2424: } // if
2425: } // for basisNodeIndex
2426: } // scanForFieldCallsOf
2427:
2428: /**
2429: * Scans for the left and right sides and void statements and additionally
2430: * prefilters the raw results.
2431: */
2432: private void deepScanForClassFieldReferences(
2433: final FileStructureDescription candidateFSD,
2434: final Vector targetVector,
2435: final DefaultMutableTreeNode classBodyChildNode,
2436: final String fieldName) {
2437:
2438: // Left side scans:
2439:
2440: // Deepscan for PrimaryExpression nodes, which have children of the form
2441: // PrimaryPrefix followed by one or multiple PrimarySuffix nodes,
2442: // where the PrimaryPrefix node does *NOT* contain an AllocationExpression node.
2443: //
2444: // NOTE: There are PrimaryExpression nodes, which contain
2445: // an PrimaryPrefix node with an AllocationExpression childnode, but these ones are scanned by the
2446: // the special FieldDeclaration scan in scanReferencedObjects(), where they catch the type
2447: // of the attribute and collect it, if it's not a simple type or the type of an inner class.
2448: // Note: The last parameter treescan=true is required. This onecauses the scan to
2449: // continue reqursion after each hit, so it catches all objects in the tree.
2450: // Example: for the expression a.getx( b.getB() ), it will generate TWO entries:
2451: // 1) a.getx( b.getB() ) [=the full expression]
2452: // 2) b.getB() [=the child in the tree]
2453: //
2454:
2455: Vector targetNodes = new Vector();
2456: // Add name hits in primary expressions [ left sides ]
2457: this
2458: .deepScanForNodesWithName(targetNodes,
2459: classBodyChildNode,
2460: ParserOutputProcessor.NodeForPrimaryExpression,
2461: true /* treescan */);
2462: // Add name hits in expressions [ right sides ]
2463: this
2464: .deepScanForNodesWithName(targetNodes,
2465: classBodyChildNode,
2466: ParserOutputProcessor.NodeForExpression, true /* treescan */);
2467: // Add name hits in VariableInitializer nodes [ right sides ]
2468: this
2469: .deepScanForNodesWithName(
2470: targetNodes,
2471: classBodyChildNode,
2472: ParserOutputProcessor.NodeForVariableInitializer,
2473: true /* treescan */);
2474:
2475: for (int i = 0; i < targetNodes.size(); i++) {
2476: final DefaultMutableTreeNode this SearchStartNode = (DefaultMutableTreeNode) targetNodes
2477: .elementAt(i);
2478:
2479: // This here has been changed compared to the search for method calls.
2480: // Here we don't only search PrimaryExpressionNode's with at least
2481: // one PrimaryPrefix, but we search in a bigger scope so far.
2482:
2483: /* Debug
2484: if( thisSearchStartNode.getUserObject() instanceof Integer )
2485: {
2486: Log.Info("deepScanForClassFieldReferences> hit in fsd " +
2487: candidateFSD.className.content +
2488: " for node " +
2489: ParserTreeNode.GetStringRepresentationForNodeIdentifier(
2490: (Integer)thisSearchStartNode.getUserObject()) );
2491: }
2492: */
2493:
2494: final FieldReferenceEntry entry = this
2495: .scanNodeForFieldCalls(candidateFSD,
2496: this SearchStartNode, fieldName);
2497: if (entry != null) {
2498: this .addUniqueFieldReferenceEntryToVector(entry,
2499: targetVector);
2500: }
2501: } // for i
2502: } // deepScanForClassFieldReferences
2503:
2504: /**
2505: * Recursive method which scans the passed parentNode down to all
2506: * levels and adds any node with the passed nodeName to the targetVector.
2507: *
2508: * treeScan = true: One assumes we have a tree structure, which means
2509: * that nodes with this name can contain children at any level
2510: * with that name again. Therefore the recursion will not stop,
2511: * when a node with the passed name is found.
2512: * treeScan = false: Once a node with the passed name is found, the recursion
2513: * stops there and the children of this node (the subtree)
2514: * is not searched.
2515: *
2516: */
2517: private void deepScanForNodesWithName(final Vector targetVector,
2518: final DefaultMutableTreeNode parentNode,
2519: final Integer nodeNameIdentifier, final boolean treeScan) {
2520: // Get all level one children:
2521: final DefaultMutableTreeNode[] allChildren = this
2522: .getChildren(parentNode);
2523: final Vector searchedNodes = new Vector();
2524: for (int i = 0; i < allChildren.length; i++) {
2525: final DefaultMutableTreeNode this Child = allChildren[i];
2526: final Object userObject = this Child.getUserObject();
2527: if (userObject instanceof Integer) // it's a node
2528: {
2529: // Integer reference comparison is ok here.
2530: if ((Integer) userObject == nodeNameIdentifier) {
2531: targetVector.addElement(this Child);
2532: if (treeScan) {
2533: this
2534: .deepScanForNodesWithName(targetVector,
2535: this Child, nodeNameIdentifier,
2536: treeScan);
2537: }
2538: } else {
2539: this .deepScanForNodesWithName(targetVector,
2540: this Child, nodeNameIdentifier, treeScan);
2541: }
2542: }
2543: } // for
2544: }
2545:
2546: /**
2547: * Concatenates the PrimaryExpression children into one String and
2548: * returns it together with the linenumber in a ReferenceEntry.
2549: */
2550: private MethodReferenceEntry scanPrimaryExpressionForMethodCalls(
2551: final FileStructureDescription candidateFSD,
2552: final DefaultMutableTreeNode primaryExpressionNode,
2553: final String methodName) {
2554: MethodReferenceEntry result = null;
2555: StringWithPosition stringWithPosition = this
2556: .deepScanForIdentifier(primaryExpressionNode,
2557: methodName);
2558: if (stringWithPosition != null) {
2559: result = new MethodReferenceEntry(candidateFSD, methodName,
2560: stringWithPosition.startLine,
2561: stringWithPosition.startColumn,
2562: stringWithPosition.endLine,
2563: stringWithPosition.endColumn);
2564: }
2565: return result;
2566: } // scanPrimaryExpressionForMethodCalls
2567:
2568: private FieldReferenceEntry scanNodeForFieldCalls(
2569: final FileStructureDescription candidateFSD,
2570: final DefaultMutableTreeNode parentNode,
2571: final String fieldName) {
2572: FieldReferenceEntry result = null;
2573: StringWithPosition stringWithPosition = this
2574: .deepScanForIdentifier(parentNode, fieldName);
2575: if (stringWithPosition != null) {
2576: result = new FieldReferenceEntry(candidateFSD, fieldName,
2577: stringWithPosition.startLine,
2578: stringWithPosition.startColumn,
2579: stringWithPosition.endLine,
2580: stringWithPosition.endColumn);
2581: }
2582: return result;
2583: } // scanNodeForFieldCalls
2584:
2585: private StringWithPosition deepScanForIdentifier(
2586: final DefaultMutableTreeNode parentNode,
2587: final String identifierName) {
2588: StringWithPosition stringWithPosition = null;
2589: final DefaultMutableTreeNode[] children = this
2590: .getChildren(parentNode);
2591: int lineNumber = -1;
2592: for (int i = 0; i < children.length; i++) {
2593: if (children[i].getUserObject() instanceof TokenTreeUserObject) {
2594: final TokenTreeUserObject tokenContent = (TokenTreeUserObject) children[i]
2595: .getUserObject();
2596: if (tokenContent.getKind().equals("<IDENTIFIER>")) {
2597: if (tokenContent.getContent()
2598: .equals(identifierName)) {
2599: stringWithPosition = new StringWithPosition(
2600: identifierName, tokenContent
2601: .getStartLine(), tokenContent
2602: .getStartColumn(), tokenContent
2603: .getEndLine(), tokenContent
2604: .getEndColumn());
2605: }
2606: }
2607: }
2608: if (stringWithPosition == null) // recur
2609: {
2610: stringWithPosition = this .deepScanForIdentifier(
2611: children[i], identifierName);
2612: }
2613: if (stringWithPosition != null) {
2614: break;
2615: }
2616: } // for
2617: return stringWithPosition;
2618: } // deepScanForIdentifier
2619:
2620: /**
2621: * Recursive version - dives down to any level.
2622: * Takes all children of the passed node, and concatenates
2623: * all contents.
2624: * Additionally, the editor linenumber is returned too.
2625: *
2626: * PrimaryExpression specific: "new" tokens are skipped.
2627: */
2628: private int concatenateLeafContentsOfPrimaryExpression(
2629: final DefaultMutableTreeNode primaryExpressionNode,
2630: final StringBuffer buffer) {
2631: final DefaultMutableTreeNode[] children = this
2632: .getChildren(primaryExpressionNode);
2633: int lineNumber = -1;
2634: for (int i = 0; i < children.length; i++) {
2635: if (children[i].getUserObject() instanceof TokenTreeUserObject) {
2636: final TokenTreeUserObject tokenContent = (TokenTreeUserObject) children[i]
2637: .getUserObject();
2638: final String content = tokenContent.getContent();
2639: lineNumber = tokenContent.getStartLine();
2640: // Prefilter:
2641: // - The keyword "new" must be skipped
2642: if ((!content.equals("new"))) {
2643: buffer.append(content);
2644: }
2645: } else {
2646: lineNumber = this
2647: .concatenateLeafContentsOfPrimaryExpression(
2648: children[i], buffer);
2649: }
2650: } // for
2651: return lineNumber;
2652: } // concatenateLeafContentsOfPrimaryExpression
2653:
2654: /**
2655: * Starts the parser and returns its output = the compilationRootNode.
2656: */
2657: private ParserTreeNode getCompilationUnitNodeFor(
2658: final StringBuffer fileTextBuffer, final String fsdClassName) {
2659: boolean allWasParsedWithSuccess = true;
2660: // Create a new currentNode, which we will set as
2661: // new rootnode, once the whole parser operations has been
2662: // completed. This allows building the whole tree without
2663: // gui update slowdowns. The current node then is used
2664: // by the ParserOutputProcessor methods for the build up
2665: // of the tree :
2666: // The constructor with an int parameter automatically creates a node
2667: // which can have children.
2668: final ParserTreeNode rawParserNode = new ParserTreeNode(
2669: ParserOutputProcessor.NodeForRoot);
2670: this .currentNode = rawParserNode; // now the parser adds the structure here
2671: final CharArrayReader in = new CharArrayReader(fileTextBuffer
2672: .toString().toCharArray());
2673: final JavaCharStream javaCharStream = new JavaCharStream(in);
2674: final JavaParserTokenManager tm = new JavaParserTokenManager(
2675: javaCharStream);
2676: // Create a parser and pass this class as ParserOutputProcessor :
2677: final JavaParser p = new JavaParser(tm, this );
2678: // Now tell the parser to do its work, which will make the
2679: // parser call the ParserOutputProcessor methods :
2680: try {
2681: p.CompilationUnit();
2682: // When we come here, the parser token tree has been
2683: // fully constructed on the rawParserNode.
2684: // Now we process that token tree and transform it to
2685: // the simplier tree, which is visible to the user and whose
2686: // entry objects will tell the editor to jump to the
2687: // corresponding editor line.
2688: } catch (Exception pe) {
2689: allWasParsedWithSuccess = false;
2690: // The view then will set a red point in the title label.
2691: //ystem.out.println("FileComponentsTreeModel: ParseException \n" + pe.getMessage() );
2692: } catch (Error pError) // The tokenmanager creates errors, not exceptions
2693: {
2694:
2695: //ystem.out.println("SymbolUsageLocationSearch: Parser reports: " + pError.getMessage() +
2696: // " for " + fsdClassName );
2697:
2698: allWasParsedWithSuccess = false;
2699: // The view then will set a red point in the title label.
2700: //ystem.out.println("FileComponentsTreeModel: ParseException \n" + pe.getMessage() );
2701: }
2702: // If we encountered an exception, we still can evaulate
2703: // at least the parsed elements upto the line, which
2704: // has caused this exception.
2705:
2706: // return postprocessed node :
2707: // The rawParserNode has one child called CompilationUnit,
2708: // so we pass directly this one :
2709: return (ParserTreeNode) rawParserNode.getChildAt(0);
2710: } // getCompilationRootNode
2711:
2712: /**
2713: * Implementation of ParserOutputProcessor.
2714: * Called by the parser when it encounters a new node.
2715: */
2716: public void addNode(final Integer nodeIdentifier) {
2717: // Insert a new node at the currentnode:
2718: // Note: The constructor with an int parameter automatically creates
2719: // a node, which can have children.
2720: ParserTreeNode newNode = new ParserTreeNode(nodeIdentifier);
2721: this .currentNode.add(newNode);
2722: // and update the currentNode :
2723: this .currentNode = newNode;
2724: }
2725:
2726: /**
2727: * Implementation of ParserOutputProcessor.
2728: * Called by the parser when it returns from a previously
2729: * encountered node (for which it has called addNode)
2730: */
2731: public void returnFromNode(final Integer nodeIdentifier) {
2732: // Just update the currentNode :
2733: if (this .currentNode.getParent() != null) {
2734: this .currentNode = (ParserTreeNode) this .currentNode
2735: .getParent();
2736: }
2737: }
2738:
2739: /**
2740: * Implementation of ParserOutputProcessor.
2741: * Called by the parser when it has encountered a token
2742: * at the current treeposition, which is defined by all
2743: * already received calls of addNode() and returnFromNode().
2744: */
2745: public void addLeaf(final Token token) {
2746: // tokenImage is defined in the implemented JavaParserConstants Interface.
2747: String kindString = tokenImage[token.kind];
2748: TokenTreeUserObject userObject = new TokenTreeUserObject(
2749: token.image,
2750: kindString,
2751: true, // always display kind for token tree's
2752: token.beginLine, token.endLine, token.beginColumn,
2753: token.endColumn,
2754: FileComponentsTreeCellRenderer.UseTokenLeafIcon);
2755: // The constructor with a TokenTreeUserObject parameter automatically
2756: // creates a leaf.
2757: ParserTreeNode newNode = new ParserTreeNode(userObject);
2758: this .currentNode.add(newNode);
2759: }
2760:
2761: /**
2762: * Adds the passed reference to the vector, if the vector doesn't
2763: * contain an equal reference already.
2764: */
2765: private void addUniqueObjectToVector(final Object object,
2766: final Vector vector) {
2767: boolean isAlreadyExisting = false;
2768: for (int i = 0; i < vector.size(); i++) {
2769: final Object s = vector.elementAt(i);
2770: if (s.equals(object)) {
2771: isAlreadyExisting = true;
2772: break;
2773: }
2774: }
2775: if (!isAlreadyExisting) {
2776: vector.addElement(object);
2777: }
2778: } // addUniqueObjectToVector
2779:
2780: /**
2781: * Adds the passed reference to the vector, if the vector doesn't
2782: * contain an equal reference already.
2783: */
2784: private void addUniqueMethodReferenceEntryToVector(
2785: final MethodReferenceEntry entry, final Vector vector) {
2786: boolean isAlreadyExisting = false;
2787: for (int i = 0; i < vector.size(); i++) {
2788: final MethodReferenceEntry s = (MethodReferenceEntry) vector
2789: .elementAt(i);
2790: if (s.equals(entry)) {
2791: isAlreadyExisting = true;
2792: break;
2793: }
2794: }
2795: if (!isAlreadyExisting) {
2796: vector.addElement(entry);
2797: }
2798: } // addUniqueMethodReferenceEntryToVector
2799:
2800: /**
2801: * Adds the passed reference to the vector, if the vector doesn't
2802: * contain an equal reference already.
2803: */
2804: private void addUniqueFieldReferenceEntryToVector(
2805: final FieldReferenceEntry entry, final Vector vector) {
2806: boolean isAlreadyExisting = false;
2807: for (int i = 0; i < vector.size(); i++) {
2808: final FieldReferenceEntry s = (FieldReferenceEntry) vector
2809: .elementAt(i);
2810: if (s.equals(entry)) {
2811: isAlreadyExisting = true;
2812: break;
2813: }
2814: }
2815: if (!isAlreadyExisting) {
2816: vector.addElement(entry);
2817: }
2818: } // addUniqueFieldReferenceEntryToVector
2819:
2820: private DefaultMutableTreeNode[] getAllChildNodesWithName(
2821: final DefaultMutableTreeNode parentNode,
2822: final Integer nodeNameIdentifier) {
2823: final DefaultMutableTreeNode[] allChildren = this
2824: .getChildren(parentNode);
2825: final Vector searchedNodes = new Vector();
2826: for (int i = 0; i < allChildren.length; i++) {
2827: final DefaultMutableTreeNode this Child = allChildren[i];
2828: final Object userObject = this Child.getUserObject();
2829: if (userObject instanceof Integer) {
2830: // Integer reference comparison is ok here.
2831: if ((Integer) userObject == nodeNameIdentifier) {
2832: searchedNodes.addElement(this Child);
2833: }
2834: }
2835: }
2836: final DefaultMutableTreeNode[] searchedNodeArray = new DefaultMutableTreeNode[searchedNodes
2837: .size()];
2838: searchedNodes.copyInto(searchedNodeArray);
2839: return searchedNodeArray;
2840: }
2841:
2842: /**
2843: * Returns all first level children
2844: */
2845: private DefaultMutableTreeNode[] getChildren(
2846: final DefaultMutableTreeNode parentNode) {
2847: int childCount = parentNode.getChildCount();
2848: DefaultMutableTreeNode[] children = new DefaultMutableTreeNode[childCount];
2849: for (int i = 0; i < childCount; i++) {
2850: children[i] = (DefaultMutableTreeNode) parentNode
2851: .getChildAt(i);
2852: } // for
2853: return children;
2854: } // getChildren
2855:
2856: /**
2857: * A utility method, used for method call location search.
2858: *
2859: * It gets all classes of the inheritance tree and all interfaces, which explicitly contain the
2860: * searched method.
2861: * @param fsdManager the fsd manager
2862: * @param basisTargetFSD one FSD, which contains the searched method explicitly.
2863: * @param methodName the name of the searched method. Signatures are not considered here.
2864: */
2865: public FileStructureDescription[] getRelatedFSDsContainingMethod(
2866: FileStructureDescriptionManager fsdManager,
2867: FileStructureDescription basisTargetFSD, String methodName) {
2868:
2869: // The method, which is searched, is coded inside the source associated with the basisTargetFSD:
2870: FileStructureDescription[] basisTargetParentFSDs = fsdManager
2871: .getParentChainForFSD(basisTargetFSD);
2872: Vector classesContainingTheSearchedMethod = new Vector();
2873: classesContainingTheSearchedMethod.addElement(basisTargetFSD);
2874: // Step one:
2875: // Search and add all classes, which inherit from the basisTarget class,
2876: // because these one either are capable of calling the super method of
2877: // the basisTarget class, or if they have overwritten it, we add them
2878: // also [easier and less errorprone in general - the programmer could
2879: // have forgotten, that the method is overwritten and this way
2880: // is informed about this in some way ]:
2881: // We need all project fsd's:
2882: FileStructureDescription[] allProjectFSDs = fsdManager
2883: .getAllProjectFSDs();
2884: FileStructureDescription[] workParentChainFSDs = null;
2885: // take the highest parent of the basisTargetFSD as reference:
2886: FileStructureDescription highestParentFSD = basisTargetFSD;
2887: if (basisTargetParentFSDs != null) {
2888: // Follow the chain to get the highest parent, which still lies in the project space:
2889: for (int k = 0; k < basisTargetParentFSDs.length; k++) {
2890: if (basisTargetParentFSDs[k].belongsToProject) {
2891: highestParentFSD = basisTargetParentFSDs[k];
2892: } else {
2893: break; // left project space
2894: }
2895: }
2896: }
2897: // Search:
2898: for (int i = 0; i < allProjectFSDs.length; i++) {
2899: workParentChainFSDs = fsdManager
2900: .getParentChainForFSD_ProjectOnly(allProjectFSDs[i]);
2901: if (workParentChainFSDs != null) {
2902: for (int k = 0; k < workParentChainFSDs.length; k++) {
2903: // reference comparison
2904: if (workParentChainFSDs[k] == basisTargetFSD) {
2905: // The allProjectFSD[i] is a child of basisTargetFSD, in any level.
2906: this .addUniqueObjectToVector(allProjectFSDs[i],
2907: classesContainingTheSearchedMethod);
2908: }
2909: }
2910: }
2911: } // for
2912: workParentChainFSDs = null; // assist the GC finally
2913: allProjectFSDs = null; // assist the GC finally
2914:
2915: // We make the parentclasses / [mutliple] possible interfaces - tree flat,
2916: // but only add parentclasses/interfaces, which do contain the searched method [with
2917: // ANY signature] too:
2918: // Step two: Just add the basis class, all parents and all interfaces [check for the method after this]:
2919: Vector allInterfaces = new Vector(0);
2920: fsdManager.addImplementedInterfaceFSDsOf(basisTargetFSD,
2921: allInterfaces);
2922: // Go back the parentchain and for each parent fsd, test/add implemented
2923: // interfaces, which contain the method (any signature) too:
2924: for (int i = 0; i < basisTargetParentFSDs.length; i++) {
2925: final FileStructureDescription parentFSD = basisTargetParentFSDs[i];
2926: // Only for projectfiles:
2927: if (parentFSD.belongsToProject) {
2928: this .addUniqueObjectToVector(parentFSD,
2929: classesContainingTheSearchedMethod);
2930: // Add all implemented interfaces:
2931: fsdManager.addImplementedInterfaceFSDsOf(parentFSD,
2932: allInterfaces);
2933: }
2934: } // for
2935: // Now add all interface fsd's to the classesContainingTheSearchedMethod vector,
2936: // IF they contain a method (with any signature) of the wanted name:
2937: for (int k = 0; k < allInterfaces.size(); k++) {
2938: if (this .hasMemberMethodWithName(
2939: (FileStructureDescription) allInterfaces
2940: .elementAt(k), methodName)) {
2941: classesContainingTheSearchedMethod
2942: .addElement(allInterfaces.elementAt(k));
2943: //final FileStructureDescription iface = (FileStructureDescription)allInterfaces.elementAt(k);
2944: //ystem.out.println("Interface " + iface.fullyQualifiedClassNameBuffer.toString() +
2945: // " contains method " + methodName );
2946: }
2947: }
2948: // Copy them into an array:
2949: final FileStructureDescription[] targetClassFSDs = new FileStructureDescription[classesContainingTheSearchedMethod
2950: .size()];
2951: classesContainingTheSearchedMethod.copyInto(targetClassFSDs);
2952: return targetClassFSDs;
2953: } // getRelatedFSDsContainingMethod
2954:
2955: private boolean hasMemberMethodWithName(
2956: final FileStructureDescription fsd, final String methodName) {
2957: boolean methodNameFound = false;
2958: for (int i = 0; i < fsd.methodDescriptions.size(); i++) {
2959: final FileStructureDescriptionForMethod methodFSD = (FileStructureDescriptionForMethod) fsd.methodDescriptions
2960: .elementAt(i);
2961: if (methodFSD.name.content.equals(methodName)) {
2962: methodNameFound = true;
2963: break;
2964: }
2965: } // for
2966: return methodNameFound;
2967: } // hasMethodWithName
2968:
2969: /**
2970: * A utility method, used for attribute call location search.
2971: *
2972: * It gets all classes of the inheritance tree and all interfaces, which explicitly contain the
2973: * searched attribute.
2974: * @param fsdManager the fsd manager
2975: * @param basisTargetFSD one FSD, which contains the searched method explicitly.
2976: * @param attributeName the name of the searched attribute.
2977: */
2978: public FileStructureDescription[] getRelatedFSDsContainingAttribute(
2979: FileStructureDescriptionManager fsdManager,
2980: FileStructureDescription basisTargetFSD,
2981: String attributeName) {
2982: FileStructureDescription[] basisTargetParentFSDs = fsdManager
2983: .getParentChainForFSD(basisTargetFSD);
2984: Vector classesContainingTheSearchedAttribute = new Vector();
2985: classesContainingTheSearchedAttribute
2986: .addElement(basisTargetFSD);
2987: // Step one:
2988: // Search and add all classes, which inherit from the basisTarget class,
2989: // because these one either are capable of calling the super method of
2990: // the basisTarget class, or if they have overwritten it, we add them
2991: // also [easier and less errorprone in general - the programmer could
2992: // have forgotten, that the method is overwritten and this way
2993: // is informed about this in some way ]:
2994: // We need all project fsd's:
2995: FileStructureDescription[] allProjectFSDs = fsdManager
2996: .getAllProjectFSDs();
2997: FileStructureDescription[] workParentChainFSDs = null;
2998: // take the highest parent of the basisTargetFSD as reference:
2999: FileStructureDescription highestParentFSD = basisTargetFSD;
3000: if (basisTargetParentFSDs != null) {
3001: // Follow the chain to get the highest parent, which still lies in the project space:
3002: for (int k = 0; k < basisTargetParentFSDs.length; k++) {
3003: if (basisTargetParentFSDs[k].belongsToProject) {
3004: highestParentFSD = basisTargetParentFSDs[k];
3005: } else {
3006: break; // left project space
3007: }
3008: }
3009: }
3010: // Search:
3011: for (int i = 0; i < allProjectFSDs.length; i++) {
3012: workParentChainFSDs = fsdManager
3013: .getParentChainForFSD_ProjectOnly(allProjectFSDs[i]);
3014: if (workParentChainFSDs != null) {
3015: for (int k = 0; k < workParentChainFSDs.length; k++) {
3016: // reference comparison
3017: if (workParentChainFSDs[k] == basisTargetFSD) {
3018: // The allProjectFSD[i] is a child of basisTargetFSD, in any level.
3019: this .addUniqueObjectToVector(allProjectFSDs[i],
3020: classesContainingTheSearchedAttribute);
3021: }
3022: }
3023: }
3024: } // for
3025: workParentChainFSDs = null; // assist the GC finally
3026: allProjectFSDs = null; // assist the GC finally
3027:
3028: // We make the parentclasses / [mutliple] possible interfaces - tree flat,
3029: // but only add parentclasses/interfaces, which do contain the searched method [with
3030: // ANY signature] too:
3031: // Step two: Just add the basis class, all parents and all interfaces [check for the method after this]:
3032: Vector allInterfaces = new Vector(0);
3033: fsdManager.addImplementedInterfaceFSDsOf(basisTargetFSD,
3034: allInterfaces);
3035: // Go back the parentchain and for each parent fsd, test/add implemented
3036: // interfaces, which contain the attribute as member :
3037: for (int i = 0; i < basisTargetParentFSDs.length; i++) {
3038: final FileStructureDescription parentFSD = basisTargetParentFSDs[i];
3039: // Only for projectfiles:
3040: if (parentFSD.belongsToProject) {
3041: this .addUniqueObjectToVector(parentFSD,
3042: classesContainingTheSearchedAttribute);
3043: // Add all implemented interfaces:
3044: fsdManager.addImplementedInterfaceFSDsOf(parentFSD,
3045: allInterfaces);
3046: }
3047: } // for
3048: // Now add all interface fsd's to the classesContainingTheSearchedAttribute vector,
3049: // IF they contain an attribute the wanted name:
3050: for (int k = 0; k < allInterfaces.size(); k++) {
3051: if (this .hasMemberAttributeWithName(
3052: (FileStructureDescription) allInterfaces
3053: .elementAt(k), attributeName)) {
3054: classesContainingTheSearchedAttribute
3055: .addElement(allInterfaces.elementAt(k));
3056: //final FileStructureDescription iface = (FileStructureDescription)allInterfaces.elementAt(k);
3057: //ystem.out.println("Interface " + iface.fullyQualifiedClassNameBuffer.toString() +
3058: // " contains method " + methodName );
3059: }
3060: }
3061: // Copy them into an array:
3062: final FileStructureDescription[] targetClassFSDs = new FileStructureDescription[classesContainingTheSearchedAttribute
3063: .size()];
3064: classesContainingTheSearchedAttribute.copyInto(targetClassFSDs);
3065: return targetClassFSDs;
3066: }
3067:
3068: private boolean hasMemberAttributeWithName(
3069: final FileStructureDescription fsd,
3070: final String attributeName) {
3071: boolean attributeNameFound = false;
3072: for (int i = 0; i < fsd.fieldDescriptions.size(); i++) {
3073: final FileStructureDescriptionForField fieldFSD = (FileStructureDescriptionForField) fsd.fieldDescriptions
3074: .elementAt(i);
3075: if (fieldFSD.objectNameWithPosition.content
3076: .equals(attributeName)) {
3077: attributeNameFound = true;
3078: break;
3079: }
3080: } // for
3081: return attributeNameFound;
3082: } // hasMemberAttributeWithName
3083:
3084: /**
3085: * GC assistance
3086: */
3087: public void freeMemory() {
3088: this .projectFrame = null;
3089: if (this .currentNode != null) {
3090: this .currentNode.removeAllChildren();
3091: this .currentNode = null;
3092: }
3093: } // freeMemory
3094:
3095: } // SymbolUsageLocationSearch
|