ada.editor/src/org/netbeans/modules/ada/editor/parser/AdaSemanticAnalyzer.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.
raster@14180
     1
/*
raster@14180
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
raster@14180
     3
 *
raster@14180
     4
 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
raster@14180
     5
 *
raster@14180
     6
 * The contents of this file are subject to the terms of either the GNU
raster@14180
     7
 * General Public License Version 2 only ("GPL") or the Common
raster@14180
     8
 * Development and Distribution License("CDDL") (collectively, the
raster@14180
     9
 * "License"). You may not use this file except in compliance with the
raster@14180
    10
 * License. You can obtain a copy of the License at
raster@14180
    11
 * http://www.netbeans.org/cddl-gplv2.html
raster@14180
    12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
raster@14180
    13
 * specific language governing permissions and limitations under the
raster@14180
    14
 * License.  When distributing the software, include this License Header
raster@14180
    15
 * Notice in each file and include the License file at
raster@14180
    16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
raster@14180
    17
 * particular file as subject to the "Classpath" exception as provided
raster@14180
    18
 * by Sun in the GPL Version 2 section of the License file that
raster@14180
    19
 * accompanied this code. If applicable, add the following below the
raster@14180
    20
 * License Header, with the fields enclosed by brackets [] replaced by
raster@14180
    21
 * your own identifying information:
raster@14180
    22
 * "Portions Copyrighted [year] [name of copyright owner]"
raster@14180
    23
 *
raster@14180
    24
 * If you wish your version of this file to be governed by only the CDDL
raster@14180
    25
 * or only the GPL Version 2, indicate your decision by adding
raster@14180
    26
 * "[Contributor] elects to include this software in this distribution
raster@14180
    27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
raster@14180
    28
 * single choice of license, a recipient has the option to distribute
raster@14180
    29
 * your version of this file under either the CDDL, the GPL Version 2 or
raster@14180
    30
 * to extend the choice of license to its licensees as provided above.
raster@14180
    31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
raster@14180
    32
 * Version 2 license, then the option applies only if the new code is
raster@14180
    33
 * made subject to such option by the copyright holder.
raster@14180
    34
 *
raster@14180
    35
 * Contributor(s):
raster@14180
    36
 *
raster@14180
    37
 * Portions Copyrighted 2008 Sun Microsystems, Inc.
raster@14180
    38
 */
raster@14180
    39
package org.netbeans.modules.ada.editor.parser;
raster@14180
    40
raster@14523
    41
import java.util.ArrayList;
raster@14523
    42
import java.util.EnumSet;
raster@14523
    43
import java.util.HashMap;
raster@14523
    44
import java.util.List;
raster@14180
    45
import java.util.Map;
raster@14180
    46
import java.util.Set;
raster@16367
    47
import java.util.logging.Level;
raster@16367
    48
import java.util.logging.Logger;
raster@14523
    49
import org.netbeans.modules.ada.editor.ast.ASTNode;
raster@14523
    50
import org.netbeans.modules.ada.editor.ast.nodes.Block;
raster@14695
    51
import org.netbeans.modules.ada.editor.ast.nodes.BodyDeclaration.Modifier;
raster@14539
    52
import org.netbeans.modules.ada.editor.ast.nodes.FieldsDeclaration;
raster@14523
    53
import org.netbeans.modules.ada.editor.ast.nodes.Identifier;
raster@14695
    54
import org.netbeans.modules.ada.editor.ast.nodes.MethodDeclaration;
raster@14523
    55
import org.netbeans.modules.ada.editor.ast.nodes.PackageBody;
raster@14523
    56
import org.netbeans.modules.ada.editor.ast.nodes.PackageSpecification;
raster@14695
    57
import org.netbeans.modules.ada.editor.ast.nodes.TypeDeclaration;
raster@16367
    58
import org.netbeans.modules.ada.editor.ast.nodes.TypeName;
raster@14539
    59
import org.netbeans.modules.ada.editor.ast.nodes.Variable;
raster@14523
    60
import org.netbeans.modules.ada.editor.ast.nodes.visitors.DefaultVisitor;
raster@15779
    61
import org.netbeans.modules.csl.api.ColoringAttributes;
raster@15779
    62
import org.netbeans.modules.csl.api.OffsetRange;
raster@15779
    63
import org.netbeans.modules.csl.api.SemanticAnalyzer;
raster@15779
    64
import org.netbeans.modules.csl.spi.ParserResult;
raster@15779
    65
import org.netbeans.modules.parsing.api.Snapshot;
raster@15779
    66
import org.netbeans.modules.parsing.spi.Parser.Result;
raster@15779
    67
import org.netbeans.modules.parsing.spi.Scheduler;
raster@15779
    68
import org.netbeans.modules.parsing.spi.SchedulerEvent;
raster@14180
    69
raster@14180
    70
/**
raster@14539
    71
 * Based on org.netbeans.modules.php.editor.parser.SemanticAnalysis
raster@14180
    72
 *
raster@14180
    73
 * @author Andrea Lucarelli
raster@14180
    74
 */
raster@15779
    75
public class AdaSemanticAnalyzer extends SemanticAnalyzer {
raster@14180
    76
raster@16367
    77
    private static final Logger LOGGER = Logger.getLogger(AdaSemanticAnalyzer.class.getName());
raster@16367
    78
raster@14523
    79
    public static final EnumSet<ColoringAttributes> UNUSED_FIELD_SET = EnumSet.of(ColoringAttributes.UNUSED, ColoringAttributes.FIELD);
raster@14523
    80
    public static final EnumSet<ColoringAttributes> UNUSED_METHOD_SET = EnumSet.of(ColoringAttributes.UNUSED, ColoringAttributes.METHOD);
raster@14523
    81
    private boolean cancelled;
raster@14523
    82
    private Map<OffsetRange, Set<ColoringAttributes>> semanticHighlights;
raster@14523
    83
raster@14523
    84
    public AdaSemanticAnalyzer() {
raster@14523
    85
        semanticHighlights = null;
raster@16367
    86
        LOGGER.setLevel(Level.FINE);
raster@14523
    87
    }
raster@14523
    88
raster@14180
    89
    public Map<OffsetRange, Set<ColoringAttributes>> getHighlights() {
raster@14523
    90
        return semanticHighlights;
raster@14180
    91
    }
raster@14180
    92
raster@14180
    93
    public void cancel() {
raster@14523
    94
        cancelled = true;
raster@14180
    95
    }
raster@14180
    96
raster@15779
    97
    public void run(ParserResult compilationInfo) throws Exception {
raster@14180
    98
    }
raster@14180
    99
raster@14523
   100
    protected final synchronized boolean isCancelled() {
raster@14523
   101
        return cancelled;
raster@14523
   102
    }
raster@14523
   103
raster@14523
   104
    protected final synchronized void resume() {
raster@14523
   105
        cancelled = false;
raster@14523
   106
    }
raster@14523
   107
raster@15779
   108
    @Override
raster@15779
   109
    public void run(Result r, SchedulerEvent event) {
raster@15779
   110
        resume();
raster@14523
   111
raster@15779
   112
        if (isCancelled()) {
raster@15779
   113
            return;
raster@14523
   114
        }
raster@15779
   115
raster@15779
   116
        AdaParseResult result = (AdaParseResult) r;
raster@15779
   117
        Map<OffsetRange, Set<ColoringAttributes>> highlights =
raster@15779
   118
                new HashMap<OffsetRange, Set<ColoringAttributes>>(100);
raster@15779
   119
raster@15779
   120
        if (result.getProgram() != null) {
raster@15779
   121
            result.getProgram().accept(new SemanticHighlightVisitor(highlights, result.getSnapshot()));
raster@15779
   122
raster@15779
   123
            if (highlights.size() > 0) {
raster@15779
   124
                semanticHighlights = highlights;
raster@15779
   125
            } else {
raster@15779
   126
                semanticHighlights = null;
raster@15779
   127
            }
raster@15779
   128
        }
raster@15779
   129
    }
raster@15779
   130
raster@15779
   131
    @Override
raster@15779
   132
    public int getPriority() {
raster@15779
   133
        return 0;
raster@15779
   134
    }
raster@15779
   135
raster@15779
   136
    @Override
raster@15779
   137
    public Class<? extends Scheduler> getSchedulerClass() {
raster@15779
   138
        return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
raster@14523
   139
    }
raster@14523
   140
raster@14523
   141
    private class SemanticHighlightVisitor extends DefaultVisitor {
raster@14523
   142
raster@14523
   143
        private class IdentifierColoring {
raster@14523
   144
raster@14523
   145
            public Identifier identifier;
raster@14523
   146
            public Set<ColoringAttributes> coloring;
raster@14523
   147
raster@14523
   148
            public IdentifierColoring(Identifier identifier, Set<ColoringAttributes> coloring) {
raster@14523
   149
                this.identifier = identifier;
raster@14523
   150
                this.coloring = coloring;
raster@14523
   151
            }
raster@14523
   152
        }
raster@14523
   153
        Map<OffsetRange, Set<ColoringAttributes>> highlights;
raster@14523
   154
        // for unused private fields: name, varible
raster@14523
   155
        // if isused, then it's deleted from the list and marked as the field
raster@14523
   156
        private final Map<String, IdentifierColoring> privateFieldsUsed;
raster@14523
   157
        // for unsed private method: name, identifier
raster@14523
   158
        private final Map<String, IdentifierColoring> privateMethod;
raster@14523
   159
        // this is holder of blocks, which has to be scanned for usages in the class.
raster@14523
   160
        private List<Block> needToScan = new ArrayList<Block>();
raster@15779
   161
        private final Snapshot snapshot;
raster@14523
   162
raster@15779
   163
        public SemanticHighlightVisitor(Map<OffsetRange, Set<ColoringAttributes>> highlights, Snapshot snapshot) {
raster@14523
   164
            this.highlights = highlights;
raster@14523
   165
            privateFieldsUsed = new HashMap<String, IdentifierColoring>();
raster@14523
   166
            privateMethod = new HashMap<String, IdentifierColoring>();
raster@15779
   167
            this.snapshot = snapshot;
raster@14523
   168
        }
raster@14523
   169
raster@14523
   170
        private void addOffsetRange(ASTNode node, Set<ColoringAttributes> coloring) {
raster@15779
   171
            int start = snapshot.getOriginalOffset(node.getStartOffset());
raster@15779
   172
            if (start > -1) {
raster@15779
   173
                int end = start + node.getEndOffset() - node.getStartOffset();
raster@15779
   174
                highlights.put(new OffsetRange(start, end), coloring);
raster@14523
   175
            }
raster@14523
   176
        }
raster@14523
   177
raster@14523
   178
        @Override
raster@14523
   179
        public void visit(PackageSpecification node) {
raster@14523
   180
            if (isCancelled()) {
raster@14523
   181
                return;
raster@14523
   182
            }
raster@14523
   183
            Identifier name = node.getName();
raster@14523
   184
            addOffsetRange(name, ColoringAttributes.CLASS_SET);
raster@14539
   185
            // Check if package name end is present
raster@14539
   186
            if (node.getNameEnd().getName() != null) {
raster@14539
   187
                Identifier nameEnd = node.getNameEnd();
raster@14539
   188
                addOffsetRange(nameEnd, ColoringAttributes.CLASS_SET);
raster@14523
   189
            }
raster@14523
   190
            needToScan = new ArrayList<Block>();
raster@14539
   191
            if (node.getBody() != null) {
raster@14539
   192
                node.getBody().accept(this);
raster@14523
   193
raster@14523
   194
                // find all usages in the method bodies
raster@14523
   195
                for (Block block : needToScan) {
raster@14523
   196
                    block.accept(this);
raster@14523
   197
                }
raster@14523
   198
                // are there unused private fields?
raster@14523
   199
                for (IdentifierColoring item : privateFieldsUsed.values()) {
raster@14695
   200
                    addOffsetRange(item.identifier, UNUSED_FIELD_SET);
raster@14523
   201
                }
raster@14523
   202
raster@14523
   203
                // are there unused private methods?
raster@14523
   204
                for (IdentifierColoring item : privateMethod.values()) {
raster@14695
   205
                    addOffsetRange(item.identifier, UNUSED_METHOD_SET);
raster@14695
   206
                }
raster@14695
   207
            }
raster@14695
   208
        }
raster@14695
   209
raster@14695
   210
        @Override
raster@14539
   211
        public void visit(PackageBody node) {
raster@14539
   212
            if (isCancelled()) {
raster@14539
   213
                return;
raster@14539
   214
            }
raster@14539
   215
            Identifier name = node.getName();
raster@14539
   216
            addOffsetRange(name, ColoringAttributes.CLASS_SET);
raster@14539
   217
            // Check if package name end is present
raster@14539
   218
            if (node.getNameEnd().getName() != null) {
raster@14539
   219
                Identifier nameEnd = node.getNameEnd();
raster@14539
   220
                addOffsetRange(nameEnd, ColoringAttributes.CLASS_SET);
raster@14539
   221
            }
raster@14539
   222
            needToScan = new ArrayList<Block>();
raster@14539
   223
            if (node.getBody() != null) {
raster@14539
   224
                node.getBody().accept(this);
raster@14539
   225
raster@14539
   226
                // find all usages in the method bodies
raster@14539
   227
                for (Block block : needToScan) {
raster@14539
   228
                    block.accept(this);
raster@14539
   229
                }
raster@14539
   230
                // are there unused private fields?
raster@14539
   231
                for (IdentifierColoring item : privateFieldsUsed.values()) {
raster@14695
   232
                    addOffsetRange(item.identifier, UNUSED_FIELD_SET);
raster@14539
   233
                }
raster@14539
   234
raster@14539
   235
                // are there unused private methods?
raster@14539
   236
                for (IdentifierColoring item : privateMethod.values()) {
raster@14695
   237
                    addOffsetRange(item.identifier, UNUSED_METHOD_SET);
raster@14539
   238
                }
raster@14539
   239
            }
raster@14539
   240
        }
raster@14539
   241
raster@14539
   242
        @Override
raster@16367
   243
        public void visit(MethodDeclaration method) {
raster@16367
   244
            if (isCancelled()) {
raster@16367
   245
                return;
raster@16367
   246
            }
raster@16367
   247
raster@16367
   248
            boolean isPrivate = Modifier.isPrivate(method.getModifier());
raster@16367
   249
            EnumSet<ColoringAttributes> coloring = ColoringAttributes.METHOD_SET;
raster@16367
   250
raster@16367
   251
            Identifier identifier = method.getSubrogramName();
raster@16367
   252
            addOffsetRange(identifier, coloring);
raster@16367
   253
            if (!method.isSpefication()) {
raster@16367
   254
                Identifier nameEnd = method.getSubrogramNameEnd();
raster@16367
   255
                if (nameEnd != null) {
raster@16367
   256
                    addOffsetRange(nameEnd, coloring);
raster@16367
   257
                }
raster@16367
   258
            }
raster@16367
   259
raster@16367
   260
            if (method.getSubprogramBody() != null) {
raster@16367
   261
                // don't scan the body now. It should be scanned after all declarations
raster@16367
   262
                // are known
raster@16367
   263
                Block declarations = method.getSubprogramBody().getDeclarations();
raster@16367
   264
                if (declarations != null) {
raster@16367
   265
                    declarations.accept(this);
raster@16367
   266
                }
raster@16367
   267
                Block body = method.getSubprogramBody().getBody();
raster@16367
   268
                if (body != null) {
raster@16367
   269
                    body.accept(this);
raster@16367
   270
                }
raster@16367
   271
            }
raster@16367
   272
        }
raster@16367
   273
raster@16367
   274
//        @Override
raster@16367
   275
//        public void visit(BlockStatement block) {
raster@16367
   276
//            System.out.println("BlockStatement");
raster@16367
   277
//            if (block.getLabel() != null) {
raster@16367
   278
//                EnumSet<ColoringAttributes> coloring = ColoringAttributes.METHOD_SET;
raster@16367
   279
//                Identifier identifier = block.getLabel();
raster@16367
   280
//                addOffsetRange(identifier, coloring);
raster@16367
   281
//            }
raster@16367
   282
//
raster@16367
   283
//            // don't scan the body now. It should be scanned after all declarations
raster@16367
   284
//            // are known
raster@16367
   285
//            Block declarations = block.getDeclarations();
raster@16367
   286
//            if (declarations != null) {
raster@16367
   287
//                needToScan.add(declarations);
raster@16367
   288
//            }
raster@16367
   289
//            Block body = block.getBody();
raster@16367
   290
//            if (body != null) {
raster@16367
   291
//                needToScan.add(body);
raster@16367
   292
//            }
raster@16367
   293
//        }
raster@16367
   294
raster@16367
   295
        @Override
raster@14539
   296
        public void visit(FieldsDeclaration node) {
raster@14539
   297
            if (isCancelled()) {
raster@14539
   298
                return;
raster@14539
   299
            }
raster@14539
   300
raster@14695
   301
            boolean isPrivate = Modifier.isPrivate(node.getModifier());
raster@14539
   302
            EnumSet<ColoringAttributes> coloring = ColoringAttributes.FIELD_SET;
raster@14539
   303
raster@14539
   304
            Variable[] variables = node.getVariableNames();
raster@14539
   305
            for (int i = 0; i < variables.length; i++) {
raster@14539
   306
                Variable variable = variables[i];
raster@14695
   307
                if (!isPrivate) {
raster@14695
   308
                    addOffsetRange(variable.getName(), ColoringAttributes.FIELD_SET);
raster@14695
   309
                } else {
raster@14695
   310
                    if (variable.getName() instanceof Identifier) {
raster@14720
   311
                        Identifier identifier = (Identifier) variable.getName();
raster@14695
   312
                        privateFieldsUsed.put(identifier.getName(), new IdentifierColoring(identifier, coloring));
raster@14695
   313
                    }
raster@14539
   314
                }
raster@16367
   315
                if (variable.getVariableType() != null) {
raster@16367
   316
                    TypeName typeName = variable.getVariableType();
raster@16367
   317
                    typeName.accept(this);
raster@16367
   318
                }
raster@14539
   319
            }
raster@14539
   320
        }
raster@14695
   321
raster@14695
   322
        @Override
raster@14695
   323
        public void visit(TypeDeclaration node) {
raster@14695
   324
            if (isCancelled()) {
raster@14695
   325
                return;
raster@14695
   326
            }
raster@14695
   327
raster@14695
   328
            boolean isPrivate = Modifier.isPrivate(node.getModifier());
raster@14695
   329
            EnumSet<ColoringAttributes> coloring = ColoringAttributes.FIELD_SET;
raster@14695
   330
raster@14695
   331
            Identifier id = node.getTypeName();
raster@14695
   332
            if (!isPrivate) {
raster@14695
   333
                addOffsetRange(id, ColoringAttributes.FIELD_SET);
raster@14695
   334
            } else {
raster@14695
   335
                privateFieldsUsed.put(id.getName(), new IdentifierColoring(id, coloring));
raster@14695
   336
            }
raster@14695
   337
        }
raster@16367
   338
raster@16367
   339
        @Override
raster@16367
   340
        public void visit(Variable node) {
raster@16367
   341
            if (isCancelled()) {
raster@16367
   342
                return;
raster@16367
   343
            }
raster@16367
   344
raster@16367
   345
            Identifier id = node.getName();
raster@16367
   346
            addOffsetRange(id, ColoringAttributes.FIELD_SET);
raster@16367
   347
        }
raster@16367
   348
raster@16367
   349
        @Override
raster@16367
   350
        public void visit(TypeName node) {
raster@16367
   351
            if (isCancelled()) {
raster@16367
   352
                return;
raster@16367
   353
            }
raster@16367
   354
raster@16367
   355
            if (node.isIsBaseType() == false) {
raster@16367
   356
                Identifier id = node.getTypeName();
raster@16367
   357
                addOffsetRange(id, ColoringAttributes.FIELD_SET);
raster@16367
   358
            }
raster@16367
   359
        }
raster@14523
   360
    }
raster@14180
   361
}