ada.editor/src/org/netbeans/modules/ada/editor/navigator/AdaOccurrencesFinder.java
author Andrea Lucarelli <raster@netbeans.org>
Sun, 22 Aug 2010 23:37:11 +0200
branchrelease68
changeset 16367 d2820c029d3a
parent 15779 367c7fdb5d23
permissions -rw-r--r--
Add JVM compiler support.
     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     5  *
     6  * The contents of this file are subject to the terms of either the GNU
     7  * General Public License Version 2 only ("GPL") or the Common
     8  * Development and Distribution License("CDDL") (collectively, the
     9  * "License"). You may not use this file except in compliance with the
    10  * License. You can obtain a copy of the License at
    11  * http://www.netbeans.org/cddl-gplv2.html
    12  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    13  * specific language governing permissions and limitations under the
    14  * License.  When distributing the software, include this License Header
    15  * Notice in each file and include the License file at
    16  * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    17  * particular file as subject to the "Classpath" exception as provided
    18  * by Sun in the GPL Version 2 section of the License file that
    19  * accompanied this code. If applicable, add the following below the
    20  * License Header, with the fields enclosed by brackets [] replaced by
    21  * your own identifying information:
    22  * "Portions Copyrighted [year] [name of copyright owner]"
    23  *
    24  * If you wish your version of this file to be governed by only the CDDL
    25  * or only the GPL Version 2, indicate your decision by adding
    26  * "[Contributor] elects to include this software in this distribution
    27  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    28  * single choice of license, a recipient has the option to distribute
    29  * your version of this file under either the CDDL, the GPL Version 2 or
    30  * to extend the choice of license to its licensees as provided above.
    31  * However, if you add GPL Version 2 code and therefore, elected the GPL
    32  * Version 2 license, then the option applies only if the new code is
    33  * made subject to such option by the copyright holder.
    34  *
    35  * Contributor(s):
    36  *
    37  * Portions Copyrighted 2008 Sun Microsystems, Inc.
    38  */
    39 package org.netbeans.modules.ada.editor.navigator;
    40 
    41 import java.util.Collection;
    42 import java.util.Collections;
    43 import java.util.HashMap;
    44 import java.util.LinkedList;
    45 import java.util.List;
    46 import java.util.Map;
    47 import java.util.logging.Level;
    48 import java.util.logging.Logger;
    49 import org.netbeans.modules.parsing.spi.Scheduler;
    50 import org.netbeans.modules.parsing.spi.SchedulerEvent;
    51 import org.netbeans.modules.ada.editor.CodeUtils;
    52 import org.netbeans.modules.ada.editor.ast.ASTNode;
    53 import org.netbeans.modules.ada.editor.ast.ASTUtils;
    54 import org.netbeans.modules.ada.editor.ast.nodes.FormalParameter;
    55 import org.netbeans.modules.ada.editor.ast.nodes.Identifier;
    56 import org.netbeans.modules.ada.editor.ast.nodes.MethodDeclaration;
    57 import org.netbeans.modules.ada.editor.ast.nodes.PackageBody;
    58 import org.netbeans.modules.ada.editor.ast.nodes.PackageSpecification;
    59 import org.netbeans.modules.ada.editor.ast.nodes.Scalar;
    60 import org.netbeans.modules.ada.editor.ast.nodes.SingleFieldDeclaration;
    61 import org.netbeans.modules.ada.editor.ast.nodes.SubprogramBody;
    62 import org.netbeans.modules.ada.editor.ast.nodes.SubprogramSpecification;
    63 import org.netbeans.modules.ada.editor.ast.nodes.TypeDeclaration;
    64 import org.netbeans.modules.ada.editor.ast.nodes.TypeName;
    65 import org.netbeans.modules.ada.editor.ast.nodes.Variable;
    66 import org.netbeans.modules.ada.editor.ast.nodes.visitors.DefaultVisitor;
    67 import org.netbeans.modules.ada.editor.navigator.SemiAttribute.AttributedElement;
    68 import org.netbeans.modules.ada.editor.navigator.SemiAttribute.AttributedElement.Kind;
    69 import org.netbeans.modules.csl.api.ColoringAttributes;
    70 import org.netbeans.modules.csl.api.OccurrencesFinder;
    71 import org.netbeans.modules.csl.api.OffsetRange;
    72 import org.netbeans.modules.csl.spi.GsfUtilities;
    73 import org.netbeans.modules.csl.spi.ParserResult;
    74 import org.netbeans.modules.parsing.spi.Parser.Result;
    75 
    76 /**
    77  * Based on org.netbeans.modules.php.editor.nav.OccurrencesFinderImpl
    78  *
    79  * @author Andrea Lucarelli
    80  */
    81 public class AdaOccurrencesFinder extends OccurrencesFinder {
    82 
    83     private static final Logger LOGGER = Logger.getLogger(AdaOccurrencesFinder.class.getName());
    84     private int offset;
    85     private Map<OffsetRange, ColoringAttributes> range2Attribs;
    86 
    87     public void setCaretPosition(int position) {
    88         this.offset = position;
    89         this.range2Attribs = new HashMap<OffsetRange, ColoringAttributes>();
    90     }
    91 
    92     public Map<OffsetRange, ColoringAttributes> getOccurrences() {
    93         return range2Attribs;
    94     }
    95 
    96     public void cancel() {
    97     }
    98 
    99     public void run(Result result, SchedulerEvent event) {
   100         for (OffsetRange r : compute((ParserResult) result, GsfUtilities.getLastKnownCaretOffset(result.getSnapshot(), event))) {
   101             range2Attribs.put(r, ColoringAttributes.MARK_OCCURRENCES);
   102         }
   103     }
   104 
   105     static Collection<OffsetRange> compute(final ParserResult parameter, final int offset) {
   106         final List<OffsetRange> result = new LinkedList<OffsetRange>();
   107         final List<ASTNode> path = NavUtils.underCaret(parameter, offset);
   108         final SemiAttribute attribute = SemiAttribute.semiAttribute(parameter);
   109         final AttributedElement element = NavUtils.findElement(parameter, path, offset, attribute);
   110 
   111         if (element == null) {
   112             return result;
   113         }
   114         Identifier id = null;
   115         Collections.reverse(path);
   116         for (ASTNode astNode : path) {
   117             if (astNode instanceof Identifier) {
   118                 Identifier identifier = (Identifier) astNode;
   119                 if (identifier != null) {
   120                     id = identifier;
   121                 }
   122             }
   123         }
   124 
   125         final Identifier identifier = id;
   126         final List<ASTNode> usages = new LinkedList<ASTNode>();
   127         final List<ASTNode> memberDeclaration = new LinkedList<ASTNode>();
   128 
   129         LOGGER.setLevel(Level.FINE);
   130 
   131         new DefaultVisitor() {
   132 
   133             private String pkgName = null;
   134 
   135             @Override
   136             public void visit(MethodDeclaration node) {
   137                 boolean found = false;
   138                 if (element instanceof SemiAttribute.PackageMemberElement) {
   139                     SemiAttribute.PackageMemberElement pkgEl = (SemiAttribute.PackageMemberElement) element;
   140                     String methName = CodeUtils.extractMethodName(node);
   141                     Identifier methNode = node.getSubrogramName();
   142 
   143                     if (pkgName != null && pkgEl.getPackageName().equals(pkgName) && pkgEl.getName().equals(methName)) {
   144                         memberDeclaration.add(methNode);
   145                         usages.add(methNode);
   146                         if (node.getMethodName() != null) {
   147                             usages.add(node.getSubrogramNameEnd());
   148                         }
   149                         found = true;
   150                     }
   151                 }
   152                 if (!found) {
   153                     super.visit(node);
   154                 }
   155             }
   156 
   157             @Override
   158             public void visit(TypeDeclaration node) {
   159                 boolean found = false;
   160                 if (element instanceof SemiAttribute.PackageMemberElement) {
   161                     SemiAttribute.PackageMemberElement pkgEl = (SemiAttribute.PackageMemberElement) element;
   162                     Identifier type = node.getTypeName();
   163                     String typeName = type.getName();
   164                     if (pkgName != null && pkgEl.getPackageName().equals(pkgName) && pkgEl.getName().equals(typeName)) {
   165                         memberDeclaration.add(type);
   166                         usages.add(type);
   167                         found = true;
   168                     }
   169                 }
   170                 if (!found) {
   171                     super.visit(node);
   172                 }
   173             }
   174 
   175             @Override
   176             public void visit(SingleFieldDeclaration node) {
   177                 boolean found = false;
   178                 if (element instanceof SemiAttribute.PackageMemberElement) {
   179                     SemiAttribute.PackageMemberElement pkgEl = (SemiAttribute.PackageMemberElement) element;
   180                     Variable variable = node.getName();
   181                     String varName = CodeUtils.extractVariableName(variable);
   182                     if (pkgName != null && pkgEl.getPackageName().equals(pkgName) && pkgEl.getName().equals(varName)) {
   183                         memberDeclaration.add(variable);
   184                         usages.add(variable);
   185                         found = true;
   186                     }
   187                 }
   188                 if (!found) {
   189                     super.visit(node);
   190                 }
   191             }
   192 
   193             @Override
   194             public void visit(SubprogramSpecification node) {
   195                 if (!(element instanceof SemiAttribute.PackageMemberElement)) {
   196                     if (element == attribute.getElement(node)) {
   197                         usages.add(node.getSubprogramName());
   198                     }
   199                 }
   200                 super.visit(node);
   201             }
   202 
   203             @Override
   204             public void visit(SubprogramBody node) {
   205                 if (!(element instanceof SemiAttribute.PackageMemberElement)) {
   206                     if (element == attribute.getElement(node)) {
   207                         usages.add(node.getSubprogramSpecification().getSubprogramName());
   208                         if (node.getSubprogramNameEnd().getName() != null) {
   209                             usages.add(node.getSubprogramNameEnd());
   210                         }
   211                     }
   212                 }
   213                 super.visit(node);
   214             }
   215 
   216             @Override
   217             public void visit(PackageSpecification node) {
   218                 if (element == attribute.getElement(node)) {
   219                     usages.add(node.getName());
   220                     if (node.getNameEnd().getName() != null) {
   221                         usages.add(node.getNameEnd());
   222                     }
   223                 }
   224                 pkgName = CodeUtils.extractPackageName(node);
   225                 super.visit(node);
   226                 /*
   227                  * do not mark two method decl., if happens then remove
   228                  * the superclass method.
   229                  */
   230                 while (memberDeclaration.size() > 1) {
   231                     usages.remove(memberDeclaration.remove(0));
   232                 }
   233             }
   234 
   235             @Override
   236             public void visit(PackageBody node) {
   237                 if (element == attribute.getElement(node)) {
   238                     usages.add(node.getName());
   239                     if (node.getNameEnd().getName() != null) {
   240                         usages.add(node.getNameEnd());
   241                     }
   242                 }
   243                 pkgName = CodeUtils.extractPackageName(node);
   244                 super.visit(node);
   245                 /*
   246                  * do not mark two method decl., if happens then remove
   247                  * the superclass method.
   248                  */
   249                 while (memberDeclaration.size() > 1) {
   250                     usages.remove(memberDeclaration.remove(0));
   251                 }
   252             }
   253 
   254             @Override
   255             public void visit(FormalParameter node) {
   256                 Variable parameterName = node.getParameterName();
   257                 if (parameterName != null) {
   258                     String name = parameterName.getName().getName();
   259                     if (name != null && element == attribute.getElement(parameterName)) {
   260                         usages.add(parameterName);
   261                     }
   262                 }
   263                 TypeName parameterType = CodeUtils.extractType(node.getParameterType());
   264                 if (parameterType != null) {
   265                     String name = parameterType.getTypeName().getName();
   266                     if (name != null && element == attribute.getElement(parameterType)) {
   267                         usages.add(parameterType);
   268                     }
   269                 }
   270                 super.visit(node);
   271             }
   272 
   273             @Override
   274             public void visit(Variable node) {
   275                 if (element == attribute.getElement(node)) {
   276                     usages.add(node);
   277                 }
   278                 super.visit(node);
   279             }
   280 
   281             @Override
   282             public void visit(TypeName node) {
   283                 if (element == attribute.getElement(node)) {
   284                     usages.add(node);
   285                 }
   286                 super.visit(node);
   287             }
   288 
   289             @Override
   290             public void visit(Scalar scalar) {
   291                 if (element == attribute.getElement(scalar)) {
   292                     usages.add(scalar);
   293                 }
   294                 super.visit(scalar);
   295             }
   296         }.scan(ASTUtils.getRoot(parameter));
   297 
   298         int occur = 0;
   299         for (ASTNode n : usages) {
   300             OffsetRange forNode = forNode(n, element.getKind());
   301             if (n instanceof Identifier) {
   302                 LOGGER.fine("result " + occur + ": " + ((Identifier)n).getName());
   303                 LOGGER.fine("result " + occur + ": " + forNode);
   304                 occur++;
   305             }
   306             if (forNode != null) {
   307                 result.add(forNode);
   308             }
   309         }
   310 
   311         return result;
   312     }
   313 
   314     private static OffsetRange forNode(ASTNode n, Kind kind) {
   315         OffsetRange retval = null;
   316         if (n instanceof Scalar && ((Scalar) n).getScalarType() == Scalar.Type.STRING && NavUtils.isQuoted(((Scalar) n).getStringValue())) {
   317             retval = new OffsetRange(n.getStartOffset(), n.getEndOffset());
   318         } else if (n instanceof Variable) {
   319             retval = new OffsetRange(n.getStartOffset(), n.getEndOffset());
   320         } else if (n != null) {
   321             retval = new OffsetRange(n.getStartOffset(), n.getEndOffset());
   322         }
   323         return retval;
   324     }
   325 
   326     @Override
   327     public int getPriority() {
   328         return 0;
   329     }
   330 
   331     @Override
   332     public Class<? extends Scheduler> getSchedulerClass() {
   333         return Scheduler.CURSOR_SENSITIVE_TASK_SCHEDULER;
   334     }
   335 }